import {
  Injectable,
  CanActivate,
  ExecutionContext,
  UnauthorizedException,
  Logger,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as jwt from 'jsonwebtoken';

interface ServiceTokenPayload {
  service: string;
  iat: number;
  exp?: number;
}

@Injectable()
export class ServiceAuthGuard implements CanActivate {
  private readonly logger = new Logger(ServiceAuthGuard.name);
  private readonly allowedServices: string[];
  private readonly secret: string;

  constructor(private readonly configService: ConfigService) {
    this.secret = this.configService.get<string>('SERVICE_JWT_SECRET') || '';
    const allowedServicesStr = this.configService.get<string>('ALLOWED_SERVICES') || 'identity-service,recovery-service';
    this.allowedServices = allowedServicesStr.split(',').map(s => s.trim());
    this.logger.log(`[INIT] Allowed services: ${this.allowedServices.join(', ')}`);
  }

  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest();
    const serviceToken = request.headers['x-service-token'];

    if (!serviceToken) {
      this.logger.warn('Missing service token in request');
      throw new UnauthorizedException('Missing service token');
    }

    try {
      const payload = jwt.verify(serviceToken, this.secret) as ServiceTokenPayload;

      if (!this.allowedServices.includes(payload.service)) {
        this.logger.warn(`Service not authorized: ${payload.service}`);
        throw new UnauthorizedException('Service not authorized');
      }

      // Attach service info to request for audit logging
      request.sourceService = payload.service;
      request.sourceIp = this.getClientIp(request);

      this.logger.debug(`Authenticated request from service: ${payload.service}`);
      return true;
    } catch (error) {
      if (error instanceof UnauthorizedException) {
        throw error;
      }
      this.logger.warn(`Invalid service token: ${error.message}`);
      throw new UnauthorizedException('Invalid service token');
    }
  }

  private getClientIp(request: any): string {
    return (
      request.headers['x-forwarded-for']?.split(',')[0]?.trim() ||
      request.headers['x-real-ip'] ||
      request.connection?.remoteAddress ||
      request.socket?.remoteAddress ||
      'unknown'
    );
  }
}
