import {
  All,
  Body,
  Controller,
  Headers,
  HttpCode,
  HttpStatus,
  Logger,
  Post,
  Req,
} from "@nestjs/common";
import { ApiOperation, ApiTags } from "@nestjs/swagger";
import {
  CardWebhookPayload,
  CbeBirrWebhookPayload,
  DMoneyWebhookPayload,
  EBirrWebhookPayload,
  TelebirrWebhookPayload,
  WaafiWebhookHeaders,
  WaafiWebhookPayload,
} from "@edr/payment-providers";
import { TelebirrWebhookService } from "./handlers/telebirr-webhook.service";
import { CbeBirrWebhookService } from "./handlers/cbe-birr-webhook.service";
import { EBirrWebhookService } from "./handlers/ebirr-webhook.service";
import { CardWebhookService } from "./handlers/card-webhook.service";
import { WaafiWebhookService } from "./handlers/waafi-webhook.service";
import { DMoneyWebhookService } from "./handlers/dmoney-webhook.service";

/**
 * The ONLY public surface of the payment service — the single registered webhook URL per
 * provider for the whole platform. No service auth here (provider-facing); trust comes from
 * signature verification inside each handler. Every route acks 2xx fast and never rethrows:
 * Waafi times out at 5s and does NOT retry.
 */
@ApiTags("Provider Webhooks")
@Controller("webhooks")
export class WebhooksController {
  private readonly logger = new Logger(WebhooksController.name);

  constructor(
    private readonly telebirr: TelebirrWebhookService,
    private readonly cbeBirr: CbeBirrWebhookService,
    private readonly eBirr: EBirrWebhookService,
    private readonly card: CardWebhookService,
    private readonly waafi: WaafiWebhookService,
    private readonly dMoney: DMoneyWebhookService,
  ) {}

  @All("telebirr")
  @HttpCode(HttpStatus.OK)
  @ApiOperation({
    summary: "Telebirr payment notification callback (Ethiopia)",
  })
  async receiveTelebirr(@Body() payload: TelebirrWebhookPayload) {
    this.logger.log("Telebirr webhook called");
    try {
      await this.telebirr.handle(payload);
    } catch (err) {
      this.logger.error(`Telebirr webhook handler threw: ${this.message(err)}`);
    }
    return { code: "0", message: "OK" };
  }

  @Post("cbe-birr")
  @HttpCode(HttpStatus.OK)
  @ApiOperation({
    summary: "CBE Birr payment notification callback (Ethiopia)",
  })
  async receiveCbeBirr(@Body() payload: CbeBirrWebhookPayload) {
    try {
      await this.cbeBirr.handle(payload);
    } catch (err) {
      this.logger.error(`CBE Birr webhook handler threw: ${this.message(err)}`);
    }
    return { success: true };
  }

  @Post("ebirr")
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: "eBirr payment notification callback (Ethiopia)" })
  async receiveEBirr(@Body() payload: EBirrWebhookPayload) {
    try {
      await this.eBirr.handle(payload);
    } catch (err) {
      this.logger.error(`eBirr webhook handler threw: ${this.message(err)}`);
    }
    return { code: "0000", message: "success" };
  }

  @Post("card")
  @HttpCode(HttpStatus.OK)
  @ApiOperation({
    summary: "Card payment notification callback (International)",
  })
  async receiveCard(
    @Body() payload: CardWebhookPayload,
    @Headers("stripe-signature") signature: string,
  ) {
    try {
      await this.card.handle(payload, signature);
    } catch (err) {
      this.logger.error(`Card webhook handler threw: ${this.message(err)}`);
    }
    return { received: true };
  }

  @Post("waafi")
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: "Waafi payment notification callback (Djibouti)" })
  async receiveWaafi(
    @Body() payload: WaafiWebhookPayload,
    @Headers() headers: WaafiWebhookHeaders,
    @Req() req: { rawBody?: Buffer },
  ) {

    this.logger.log("\n\n\n\nWaafi payment notification callback (Djibouti)\n\n\n\n");
    this.logger.log(
      `Waafi webhook hit: event=${payload?.event ?? "unknown"} eventId=${headers["x-webhook-event-id"] ?? "n/a"}`,
    );
    try {
      // HMAC verification must sign over the exact raw bytes Waafi sent, not re-serialized JSON.
      const rawBody = req.rawBody?.toString("utf8") ?? "";
      await this.waafi.handle(payload, rawBody, headers);
    } catch (err) {
      this.logger.error(`Waafi webhook handler threw: ${this.message(err)}`);
    }
    return { responseCode: "2001", responseMsg: "Success" };
  }

  @Post("dmoney")
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: "D-Money payment notification callback (Djibouti)" })
  async receiveDMoney(@Body() payload: DMoneyWebhookPayload) {
    try {
      await this.dMoney.handle(payload);
    } catch (err) {
      this.logger.error(`D-Money webhook handler threw: ${this.message(err)}`);
    }
    return { code: "0", msg: "Success", result: "SUCCESS" };
  }

  private message(err: unknown): string {
    return err instanceof Error ? err.message : String(err);
  }
}
