import { Controller, Get, Post, Param, Query, Request, HttpCode, HttpStatus } from "@nestjs/common";
import { InvoiceRetrievalService } from "./services/invoice-retrieval.service.js";
import { WhmcsPaymentService } from "@bff/integrations/whmcs/services/whmcs-payment.service.js";
import { WhmcsSsoService } from "@bff/integrations/whmcs/services/whmcs-sso.service.js";
import { MappingsService } from "@bff/modules/id-mappings/mappings.service.js";
import { createZodDto, ZodResponse } from "nestjs-zod";
import type { RequestWithUser } from "@bff/modules/auth/auth.types.js";

import type { Invoice, InvoiceList, InvoiceSsoLink } from "@customer-portal/domain/billing";
import {
  invoiceIdParamSchema,
  invoiceListQuerySchema,
  invoiceListSchema,
  invoiceSchema,
  invoiceSsoLinkSchema,
  invoiceSsoQuerySchema,
} from "@customer-portal/domain/billing";
import type { PaymentMethodList } from "@customer-portal/domain/payments";
import { paymentMethodListSchema } from "@customer-portal/domain/payments";

class InvoiceListQueryDto extends createZodDto(invoiceListQuerySchema) {}
class InvoiceIdParamDto extends createZodDto(invoiceIdParamSchema) {}
class InvoiceListDto extends createZodDto(invoiceListSchema) {}
class InvoiceDto extends createZodDto(invoiceSchema) {}
class InvoiceSsoLinkDto extends createZodDto(invoiceSsoLinkSchema) {}
class InvoiceSsoQueryDto extends createZodDto(invoiceSsoQuerySchema) {}
class PaymentMethodListDto extends createZodDto(paymentMethodListSchema) {}

/**
 * Billing Controller
 *
 * All request validation is handled by Zod schemas via global ZodValidationPipe.
 * Business logic is delegated to service layer.
 */
@Controller("invoices")
export class BillingController {
  constructor(
    private readonly invoicesService: InvoiceRetrievalService,
    private readonly paymentService: WhmcsPaymentService,
    private readonly ssoService: WhmcsSsoService,
    private readonly mappingsService: MappingsService
  ) {}

  @Get()
  @ZodResponse({ description: "List invoices", type: InvoiceListDto })
  async getInvoices(
    @Request() req: RequestWithUser,
    @Query() query: InvoiceListQueryDto
  ): Promise<InvoiceList> {
    return this.invoicesService.getInvoices(req.user.id, query);
  }

  @Get("payment-methods")
  @ZodResponse({ description: "List payment methods", type: PaymentMethodListDto })
  async getPaymentMethods(@Request() req: RequestWithUser): Promise<PaymentMethodList> {
    const whmcsClientId = await this.mappingsService.getWhmcsClientIdOrThrow(req.user.id);
    return this.paymentService.getPaymentMethods(whmcsClientId, req.user.id);
  }

  @Post("payment-methods/refresh")
  @HttpCode(HttpStatus.OK)
  @ZodResponse({ description: "Refresh payment methods", type: PaymentMethodListDto })
  async refreshPaymentMethods(@Request() req: RequestWithUser): Promise<PaymentMethodList> {
    const [, whmcsClientId] = await Promise.all([
      this.paymentService.invalidatePaymentMethodsCache(req.user.id),
      this.mappingsService.getWhmcsClientIdOrThrow(req.user.id),
    ]);
    return this.paymentService.getPaymentMethods(whmcsClientId, req.user.id);
  }

  @Get(":id")
  @ZodResponse({ description: "Get invoice by id", type: InvoiceDto })
  async getInvoiceById(
    @Request() req: RequestWithUser,
    @Param() params: InvoiceIdParamDto
  ): Promise<Invoice> {
    return this.invoicesService.getInvoiceById(req.user.id, params.id);
  }

  @Post(":id/sso-link")
  @HttpCode(HttpStatus.OK)
  @ZodResponse({ description: "Create invoice SSO link", type: InvoiceSsoLinkDto })
  async createSsoLink(
    @Request() req: RequestWithUser,
    @Param() params: InvoiceIdParamDto,
    @Query() query: InvoiceSsoQueryDto
  ): Promise<InvoiceSsoLink> {
    const whmcsClientId = await this.mappingsService.getWhmcsClientIdOrThrow(req.user.id);
    const ssoUrl = await this.ssoService.whmcsSsoForInvoice(whmcsClientId, params.id, query.target);
    return {
      url: ssoUrl,
      expiresAt: new Date(Date.now() + 60000).toISOString(),
    };
  }
}
