import {
  Body,
  Controller,
  HttpCode,
  HttpStatus,
  Logger,
  Optional,
  Param,
  Post,
  Req,
  UnauthorizedException,
} from '@nestjs/common';
import { Request } from 'express';
import { BancardVposService } from './bancard.service';
import { BancardLogService } from './bancard-log.service';
import { ContabilidadIntegracionService } from 'src/contabilidad/services/integracion.service';

@Controller('bancard/webhook')
export class BancardWebhookController {
  private readonly logger = new Logger(BancardWebhookController.name);

  constructor(
    private readonly bancardService: BancardVposService,
    private readonly logService: BancardLogService,
    @Optional() private readonly contabilidad: ContabilidadIntegracionService,
  ) {}

  @Post(':empresaId')
  @HttpCode(HttpStatus.OK)
  async handleWebhook(
    @Param('empresaId') empresaId: string,
    @Body() payload: any,
    @Req() req: Request,
  ) {
    const ip = req.ip ?? req.socket?.remoteAddress;

    // Verificar la firma ANTES de procesar/contabilizar. Sin esto cualquiera podría
    // POSTear {response:'S', shop_process_id} y aprobar un pago pendiente (dinero falso).
    const firmaValida = await this.bancardService.verifyWebhookSignature(payload, empresaId);
    if (!firmaValida) {
      await this.logService.logIn({
        empresaId,
        endpoint: `/bancard/webhook/${empresaId}`,
        requestBody: payload,
        httpStatus: 401,
        ipOrigen: ip,
      });
      this.logger.warn(`Webhook Bancard con firma inválida rechazado empresa=${empresaId} ip=${ip}`);
      throw new UnauthorizedException('Firma de webhook inválida');
    }

    await this.logService.logIn({
      empresaId,
      endpoint: `/bancard/webhook/${empresaId}`,
      requestBody: payload,
      httpStatus: 200,
      ipOrigen: ip,
    });

    // Responde HTTP 200 inmediatamente — trabajo pesado en async
    this.procesarWebhookAsync(payload, empresaId).catch((err) =>
      this.logger.error(`Error procesando webhook bancard empresa=${empresaId}`, err),
    );

    return { status: 'success' };
  }

  private async procesarWebhookAsync(payload: any, empresaId: string) {
    await this.bancardService.procesarWebhook(payload, empresaId);

    const shopProcessId = BigInt(payload.operation?.shop_process_id ?? 0);
    const aprobado = payload.operation?.response === 'S';
    if (!aprobado || !shopProcessId) return;

    // Buscar el pago para obtener su ID y crear asiento contable
    const pago = await this.bancardService.findPagoBySpid(shopProcessId, empresaId);
    if (!pago) return;

    if (this.contabilidad) {
      await this.contabilidad.integrarPagoBancard(pago.id).catch((err) =>
        this.logger.error(`Error contabilizando pago Bancard ${pago.id}`, err),
      );
    }
  }
}
