import {
  Body,
  Controller,
  Get,
  HttpStatus,
  Param,
  Post,
  Query,
  Res,
  UseGuards,
} from "@nestjs/common";
import {
  ApiTags,
  ApiOperation,
  ApiBearerAuth,
  ApiQuery,
  ApiOkResponse,
  ApiProduces,
} from "@nestjs/swagger";
import { Response } from "express";
import { PaymentsService } from "./payments.service";
import {
  InitiatePaymentDto,
  RefundDto,
  AddPaymentMethodDto,
  PaymentRegionEnum,
  SupportedPaymentMethodDto,
  PaymentMethodTypeEnum,
  PaymentPlatformDto,
} from "./payments.dto";
import { JwtGuard } from "../../common/jwt.guard";
import { RolesGuard } from "../../common/roles.guard";
import { Roles } from "../../common/roles.decorator";
import { UserRole } from "@prisma/client";

@ApiTags("Payment")
@Controller("payments")
export class PaymentsController {
  constructor(private service: PaymentsService) {}

  @Get("all")
  @UseGuards(JwtGuard, RolesGuard)
  @Roles(UserRole.ADMIN, UserRole.SUPERVISOR, UserRole.STAFF)
  @ApiBearerAuth("JWT-auth")
  @ApiOperation({ summary: "Get all payments with filters (staff/admin only)" })
  @ApiQuery({ name: "search", required: false })
  @ApiQuery({ name: "status", required: false })
  @ApiQuery({ name: "method", required: false })
  @ApiQuery({ name: "page", required: false })
  @ApiQuery({ name: "pageSize", required: false })
  async getAll(
    @Query("search") search?: string,
    @Query("status") status?: string,
    @Query("method") method?: string,
    @Query("page") page?: string,
    @Query("pageSize") pageSize?: string,
  ) {
    return this.service.getAll({
      search,
      status,
      method,
      page: page ? parseInt(page) : 1,
      pageSize: pageSize ? parseInt(pageSize) : 10,
    });
  }

  @Post("initiate")
  @ApiOperation({
    summary: "Initiate payment with nationality-based payment methods",
    description: `Initiates payment for a booking with support for multiple payment providers:\n\n**Ethiopian Payment Methods:**\n- TELEBIRR - Ethiopia's leading mobile money\n- CBE_BIRR - Commercial Bank of Ethiopia\n- EBIRR - Electronic payment gateway\n\n**Djiboutian Payment Methods:**\n- WAAFI - Djibouti's mobile money service\n\n**International Payment Methods:**\n- CARD - Visa, Mastercard\n- WALLET - Internal wallet balance\n\n**Multi-Currency:**\n- All transactions processed in ETB\n- Display amounts in ETB, DJF, or USD\n- Real-time exchange rate conversion`,
  })
  initiatePayment(@Body() dto: InitiatePaymentDto) {
    return this.service.initiatePayment(dto);
  }

  @Get("intents/:bookingId")
  @ApiOperation({ summary: "Get payment intent status for a booking" })
  getIntent(@Param("bookingId") bookingId: string) {
    return this.service.getIntentByBookingId(bookingId);
  }

  @Get("waafi/return")
  @ApiOperation({
    summary:
      "DEMO ONLY — confirm a Waafi payment from the browser-return params and return JSON for the " +
      "UI to display. The frontend success page forwards the Waafi query params here. Gated by " +
      "WAAFI_DEMO_TRUST_RETURN (INSECURE; real confirmation is the webhook/HPP_GETTRANINFO).",
  })
  @ApiQuery({ name: "referenceId", required: true })
  @ApiQuery({ name: "state", required: true })
  @ApiQuery({ name: "transactionId", required: false })
  waafiReturn(
    @Query("referenceId") referenceId: string,
    @Query("state") state: string,
    @Query("transactionId") transactionId: string,
  ) {
    return this.service.confirmWaafiReturnDemo({
      referenceId,
      state,
      transactionId,
    });
  }

  @Post("refund")
  @UseGuards(JwtGuard, RolesGuard)
  @Roles(UserRole.ADMIN, UserRole.STAFF, UserRole.AGENT)
  @ApiBearerAuth("JWT-auth")
  @ApiOperation({ summary: "Refund a confirmed booking (staff/agent only)" })
  refund(@Body() dto: RefundDto) {
    return this.service.refund(dto);
  }

  @Post("methods")
  @UseGuards(JwtGuard, RolesGuard)
  @Roles(UserRole.ADMIN, UserRole.STAFF)
  @ApiBearerAuth("JWT-auth")
  @ApiOperation({
    summary: "Add a payment system to the platform catalog (admin only)",
  })
  addMethod(@Body() dto: AddPaymentMethodDto) {
    return this.service.addPaymentMethod(dto);
  }

  @Get("methods")
  @ApiOperation({
    summary: "List payment systems supported by the platform",
    description:
      "Returns the global catalog of accepted payment systems. Not user-specific. Optionally filter by region to match a passenger's nationality.",
  })
  @ApiQuery({ name: "region", enum: PaymentRegionEnum, required: false })
  @ApiOkResponse({ type: [SupportedPaymentMethodDto] })
  getMethods(@Query("region") region?: PaymentRegionEnum) {
    return this.service.getSupportedPaymentMethods(region);
  }

  @Get("checkout")
  @ApiOperation({
    summary: "Browser checkout redirect",
    description:
      "Initiates payment and returns an HTML page that auto-redirects the browser to the provider checkout URL. Designed to be opened directly in a browser tab.",
  })
  @ApiQuery({ name: "bookingId", required: true })
  @ApiQuery({ name: "method", enum: PaymentMethodTypeEnum, required: true })
  @ApiQuery({ name: "platform", enum: ["web", "mobile"], required: false })
  @ApiProduces("text/html")
  async checkout(
    @Query("bookingId") bookingId: string,
    @Query("method") method: PaymentMethodTypeEnum,
    @Query("platform") platform: PaymentPlatformDto = "web",
    @Res() res: Response,
  ) {
    if (!bookingId) {
      return res
        .status(HttpStatus.BAD_REQUEST)
        .type("html")
        .send(
          this.buildErrorHtml("Missing required query parameter: bookingId"),
        );
    }
    if (!method || !Object.values(PaymentMethodTypeEnum).includes(method)) {
      return res
        .status(HttpStatus.BAD_REQUEST)
        .type("html")
        .send(
          this.buildErrorHtml("Missing or invalid query parameter: method"),
        );
    }

    try {
      const result = await this.service.initiatePayment({
        bookingId,
        method,
        platform,
      });
      const url =
        result.clientAction?.type === "REDIRECT"
          ? result.clientAction.url
          : undefined;

      if (url) {
        return res
          .status(HttpStatus.OK)
          .type("html")
          .send(this.buildRedirectHtml(url));
      }

      return res
        .status(HttpStatus.OK)
        .type("html")
        .send(this.buildStatusHtml(result.status, result.intentId));
    } catch (err: unknown) {
      const message =
        err instanceof Error ? err.message : "An unexpected error occurred";
      return res
        .status(HttpStatus.OK)
        .type("html")
        .send(this.buildErrorHtml(message));
    }
  }

  private buildRedirectHtml(url: string): string {
    const escaped = url.replace(/\"/g, "&quot;");
    return `<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="refresh" content="0;url=${escaped}">
  <title>Redirecting to payment…</title>
  <style>
    body { font-family: sans-serif; display: flex; align-items: center; justify-content: center; min-height: 100vh; margin: 0; background: #f5f5f5; }
    .card { background: #fff; border-radius: 8px; padding: 40px; text-align: center; box-shadow: 0 2px 8px rgba(0,0,0,.1); max-width: 400px; }
    .spinner { width: 40px; height: 40px; border: 4px solid #e0e0e0; border-top-color: #1a73e8; border-radius: 50%; animation: spin .8s linear infinite; margin: 0 auto 20px; }
    @keyframes spin { to { transform: rotate(360deg); } }
    p { color: #555; margin: 0 0 16px; }
    a { color: #1a73e8; }
  </style>
</head>
<body>
  <div class="card">
    <div class="spinner"></div>
    <p>Redirecting to payment provider…</p>
    <p><a href="${escaped}">Click here if you are not redirected</a></p>
  </div>
  <script>window.location.href = "${escaped}";</script>
</body>
</html>`;
  }

  private buildStatusHtml(status: string, intentId: string): string {
    return `<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Payment status</title>
  <style>
    body { font-family: sans-serif; display: flex; align-items: center; justify-content: center; min-height: 100vh; margin: 0; background: #f5f5f5; }
    .card { background: #fff; border-radius: 8px; padding: 40px; text-align: center; box-shadow: 0 2px 8px rgba(0,0,0,.1); max-width: 400px; }
    .status { font-size: 1.1rem; font-weight: 600; color: #333; margin-bottom: 8px; }
    small { color: #888; }
  </style>
</head>
<body>
  <div class="card">
    <div class="status">${status}</div>
    <small>Intent: ${intentId}</small>
  </div>
</body>
</html>`;
  }

  private buildErrorHtml(message: string): string {
    return `<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Payment error</title>
  <style>
    body { font-family: sans-serif; display: flex; align-items: center; justify-content: center; min-height: 100vh; margin: 0; background: #f5f5f5; }
    .card { background: #fff; border-radius: 8px; padding: 40px; text-align: center; box-shadow: 0 2px 8px rgba(0,0,0,.1); max-width: 400px; }
    .error { color: #d32f2f; font-weight: 600; margin-bottom: 8px; }
    p { color: #555; }
  </style>
</head>
<body>
  <div class="card">
    <div class="error">Payment could not be initiated</div>
    <p>${message}</p>
  </div>
</body>
</html>`;
  }
}
