import { Injectable, Inject, BadRequestException, NotFoundException } from "@nestjs/common";
import { Logger } from "nestjs-pino";
import type {
  Invoice,
  InvoiceList,
  InvoiceListQuery,
  InvoiceQueryStatus,
} from "@customer-portal/domain/billing";
import { INVOICE_PAGINATION, VALID_INVOICE_QUERY_STATUSES } from "@customer-portal/domain/billing";
import { WhmcsInvoiceService } from "@bff/integrations/whmcs/services/whmcs-invoice.service.js";
import { MappingsService } from "@bff/modules/id-mappings/mappings.service.js";
import { safeOperation, OperationCriticality } from "@bff/core/utils/safe-operation.util.js";
import { parseUuidOrThrow } from "@bff/core/utils/validation.util.js";

/**
 * Service responsible for retrieving invoices from WHMCS
 *
 * Validation is handled by Zod schemas at the entry point (controller).
 * This service focuses on business logic and data fetching.
 */
@Injectable()
export class InvoiceRetrievalService {
  constructor(
    private readonly whmcsInvoiceService: WhmcsInvoiceService,
    private readonly mappingsService: MappingsService,
    @Inject(Logger) private readonly logger: Logger
  ) {}

  /**
   * Get paginated invoices for a user
   */
  async getInvoices(userId: string, options: Partial<InvoiceListQuery> = {}): Promise<InvoiceList> {
    const {
      page = INVOICE_PAGINATION.DEFAULT_PAGE,
      limit = INVOICE_PAGINATION.DEFAULT_LIMIT,
      status,
    } = options;

    // Validate userId first
    parseUuidOrThrow(userId, "Invalid user ID format");
    const whmcsClientId = await this.mappingsService.getWhmcsClientIdOrThrow(userId);

    return safeOperation(
      async () => {
        const invoiceList = await this.whmcsInvoiceService.getInvoices(whmcsClientId, userId, {
          page,
          limit,
          ...(status !== undefined && { status }),
        });

        this.logger.log(`Retrieved ${invoiceList.invoices.length} invoices for user ${userId}`, {
          page,
          limit,
          status,
          totalItems: invoiceList.pagination?.totalItems,
        });

        return invoiceList;
      },
      {
        criticality: OperationCriticality.CRITICAL,
        context: `Get invoices for user ${userId}`,
        logger: this.logger,
        rethrow: [NotFoundException, BadRequestException],
        fallbackMessage: "Failed to retrieve invoices",
      }
    );
  }

  /**
   * Get individual invoice by ID
   */
  async getInvoiceById(userId: string, invoiceId: number): Promise<Invoice> {
    parseUuidOrThrow(userId, "Invalid user ID format");
    const whmcsClientId = await this.mappingsService.getWhmcsClientIdOrThrow(userId);

    return safeOperation(
      async () => {
        const invoice = await this.whmcsInvoiceService.getInvoiceById(
          whmcsClientId,
          userId,
          invoiceId
        );
        this.logger.log(`Retrieved invoice ${invoiceId} for user ${userId}`);
        return invoice;
      },
      {
        criticality: OperationCriticality.CRITICAL,
        context: `Get invoice ${invoiceId} for user ${userId}`,
        logger: this.logger,
        rethrow: [NotFoundException, BadRequestException],
        fallbackMessage: "Failed to retrieve invoice",
      }
    );
  }

  /**
   * Get invoices by status.
   *
   * Only accepts queryable statuses (Paid, Unpaid, Cancelled, Overdue, Collections).
   * Draft, Pending, and Refunded cannot be used as filters in WHMCS API.
   */
  async getInvoicesByStatus(
    userId: string,
    status: InvoiceQueryStatus,
    options: Partial<InvoiceListQuery> = {}
  ): Promise<InvoiceList> {
    const { page = INVOICE_PAGINATION.DEFAULT_PAGE, limit = INVOICE_PAGINATION.DEFAULT_LIMIT } =
      options;

    // Runtime validation for extra safety
    if (!VALID_INVOICE_QUERY_STATUSES.includes(status)) {
      throw new BadRequestException(
        `Invalid invoice status '${status}'. Valid statuses for filtering: ${VALID_INVOICE_QUERY_STATUSES.join(", ")}`
      );
    }

    return safeOperation(
      async () => this.getInvoices(userId, { page, limit, status }),
      {
        criticality: OperationCriticality.CRITICAL,
        context: `Get ${status} invoices for user ${userId}`,
        logger: this.logger,
        rethrow: [NotFoundException, BadRequestException],
        fallbackMessage: "Failed to retrieve invoices",
      }
    );
  }
}
