import {
  CanActivate,
  ExecutionContext,
  Inject,
  Injectable,
} from '@nestjs/common';
import { Request, Response } from 'express';
import { PaymeError } from '../errors';
import { PaymeGuardOptions } from '../payme';

@Injectable()
export class PaymeBasicAuthGuard implements CanActivate {
  constructor(
    @Inject('PAYME_GUARD_OPTIONS') private readonly config: PaymeGuardOptions,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest<Request>();
    const response = context.switchToHttp().getResponse<Response>();
    const token = this.extractTokenFromHeader(request);
    const trans_id = request?.body?.id;

    if (!token) {
      response.status(200).send({
        id: trans_id,
        error: PaymeError.INVALID_AUTHORIZATION,
      });
      return false;
    }

    try {
      const decoded = this.decodeToken(token);
      if (!decoded) {
        response.status(200).send({
          id: trans_id,
          error: PaymeError.INVALID_AUTHORIZATION,
        });
        return false;
      }

      const [username, password] = decoded.split(':');
      const is_valid_username = this.config.username === username;
      const is_valid_password = this.config.password === password;

      if (!is_valid_username || !is_valid_password) {
        response.status(200).send({
          id: trans_id,
          error: PaymeError.INVALID_AUTHORIZATION,
        });
        return false;
      }
    } catch (error) {
      response.status(200).send({
        id: trans_id,
        error: PaymeError.INVALID_AUTHORIZATION,
      });
      return false;
    }

    return true;
  }

  private extractTokenFromHeader(request: Request): string | undefined {
    const auth_header = request.headers['authorization'];
    if (!auth_header) return undefined;

    const [type, token] = auth_header.split(' ');
    return type === 'Basic' ? token : undefined;
  }

  private decodeToken(token: string) {
    try {
      return Buffer.from(token, 'base64').toString('utf8');
    } catch (error) {
      return undefined;
    }
  }
}
