import { BadRequestException, Inject, Injectable } from "@nestjs/common";
import { Logger } from "nestjs-pino";
import { WhmcsService } from "@bff/integrations/whmcs/whmcs.service";
import { getErrorMessage } from "@bff/core/utils/error.util";

export interface SimChargeInvoiceResult {
  invoice: { id: number; number: string; total: number; status: string };
  transactionId?: string;
}

interface OneTimeChargeParams {
  clientId: number;
  description: string;
  amountJpy: number;
  currency?: string;
  dueDate?: Date;
  notes?: string;
  failureNotesPrefix?: string;
  publicErrorMessage?: string;
  metadata?: Record<string, unknown>;
}

@Injectable()
export class SimBillingService {
  constructor(private readonly whmcs: WhmcsService, @Inject(Logger) private readonly logger: Logger) {}

  async createOneTimeCharge(params: OneTimeChargeParams): Promise<SimChargeInvoiceResult> {
    const {
      clientId,
      description,
      amountJpy,
      currency = "JPY",
      dueDate,
      notes,
      failureNotesPrefix = "Payment failed",
      publicErrorMessage,
      metadata = {},
    } = params;

    const invoice = await this.whmcs.createInvoice({
      clientId,
      description,
      amount: amountJpy,
      currency,
      dueDate,
      notes,
    });

    const paymentResult = await this.whmcs.capturePayment({
      invoiceId: invoice.id,
      amount: amountJpy,
      currency,
    });

    if (!paymentResult.success) {
      const failureMessage = `${failureNotesPrefix}: ${paymentResult.error || "unknown error"}`;
      await this.cancelInvoice(invoice.id, failureMessage);

      this.logger.error("SIM billing payment failed", {
        invoiceId: invoice.id,
        clientId,
        description,
        amountJpy,
        ...metadata,
        error: paymentResult.error,
      });

      throw new BadRequestException(publicErrorMessage ?? failureMessage);
    }

    this.logger.log("SIM billing payment captured", {
      invoiceId: invoice.id,
      clientId,
      description,
      amountJpy,
      transactionId: paymentResult.transactionId,
      ...metadata,
    });

    return {
      invoice,
      transactionId: paymentResult.transactionId,
    };
  }

  async appendInvoiceNote(invoiceId: number, note: string): Promise<void> {
    await this.whmcs.updateInvoice({
      invoiceId,
      notes: note,
    });
  }

  private async cancelInvoice(invoiceId: number, reason: string): Promise<void> {
    try {
      await this.whmcs.updateInvoice({
        invoiceId,
        status: "Cancelled",
        notes: reason,
      });
    } catch (error) {
      this.logger.error("Failed to cancel invoice after payment failure", {
        invoiceId,
        error: getErrorMessage(error),
      });
    }
  }
}

