/**
 * WHMCS Billing Provider - Mapper
 * 
 * Transforms raw WHMCS invoice data into normalized billing domain types.
 */

import type { Invoice, InvoiceItem } from "../../contract";
import { invoiceSchema } from "../../schema";
import {
  type WhmcsInvoiceRaw,
  whmcsInvoiceRawSchema,
  type WhmcsInvoiceListItem,
  whmcsInvoiceListItemSchema,
  type WhmcsInvoiceItemsRaw,
  whmcsInvoiceItemsRawSchema,
} from "./raw.types";
import { parseAmount, formatDate } from "../../../providers/whmcs/utils";

export interface TransformInvoiceOptions {
  defaultCurrencyCode?: string;
  defaultCurrencySymbol?: string;
}

// Status mapping from WHMCS to domain
const STATUS_MAP: Record<string, Invoice["status"]> = {
  draft: "Draft",
  pending: "Pending",
  "payment pending": "Pending",
  paid: "Paid",
  unpaid: "Unpaid",
  cancelled: "Cancelled",
  canceled: "Cancelled",
  overdue: "Overdue",
  refunded: "Refunded",
  collections: "Collections",
};

function mapStatus(status: string): Invoice["status"] {
  const normalized = status?.trim().toLowerCase();
  if (!normalized) {
    throw new Error("Invoice status missing");
  }

  const mapped = STATUS_MAP[normalized];
  if (!mapped) {
    throw new Error(`Unsupported WHMCS invoice status: ${status}`);
  }
  return mapped;
}

function mapItems(rawItems: unknown): InvoiceItem[] {
  if (!rawItems) return [];

  const parsed = whmcsInvoiceItemsRawSchema.parse(rawItems);
  const itemArray = Array.isArray(parsed.item) ? parsed.item : [parsed.item];
  
  return itemArray.map(item => ({
    id: item.id,
    description: item.description,
    amount: parseAmount(item.amount),
    quantity: 1,
    type: item.type,
    serviceId: typeof item.relid === "number" && item.relid > 0 ? item.relid : undefined,
  }));
}

/**
 * Transform raw WHMCS invoice data into normalized Invoice type
 */
export function transformWhmcsInvoice(
  rawInvoice: unknown,
  options: TransformInvoiceOptions = {}
): Invoice {
  const invoicePayload =
    rawInvoice && typeof (rawInvoice as { invoiceid?: unknown }).invoiceid !== "undefined"
      ? whmcsInvoiceRawSchema.parse(rawInvoice)
      : normalizeListInvoice(rawInvoice);

  const whmcsInvoice = {
    ...invoicePayload,
    invoiceid: invoicePayload.invoiceid ?? invoicePayload.id,
  };

  const currency = whmcsInvoice.currencycode || options.defaultCurrencyCode || "JPY";
  const currencySymbol =
    whmcsInvoice.currencyprefix ||
    whmcsInvoice.currencysuffix ||
    options.defaultCurrencySymbol;

  // Transform to domain model
  const invoice: Invoice = {
    id: whmcsInvoice.invoiceid ?? 0,
    number: whmcsInvoice.invoicenum || `INV-${whmcsInvoice.invoiceid}`,
    status: mapStatus(whmcsInvoice.status),
    currency,
    currencySymbol,
    total: parseAmount(whmcsInvoice.total),
    subtotal: parseAmount(whmcsInvoice.subtotal),
    tax: parseAmount(whmcsInvoice.tax) + parseAmount(whmcsInvoice.tax2),
    issuedAt: formatDate(whmcsInvoice.date || whmcsInvoice.datecreated),
    dueDate: formatDate(whmcsInvoice.duedate),
    paidDate: formatDate(whmcsInvoice.datepaid),
    description: whmcsInvoice.notes || undefined,
    items: mapItems(whmcsInvoice.items),
  };

  // Validate result against domain schema
  return invoiceSchema.parse(invoice);
}

/**
 * Transform multiple WHMCS invoices
 */
export function transformWhmcsInvoices(
  rawInvoices: unknown[],
  options: TransformInvoiceOptions = {}
): Invoice[] {
  return rawInvoices.map(raw => transformWhmcsInvoice(raw, options));
}

function normalizeListInvoice(rawInvoice: unknown): WhmcsInvoiceRaw & { id?: number } {
  const listItem: WhmcsInvoiceListItem = whmcsInvoiceListItemSchema.parse(rawInvoice);
  const invoiceid = listItem.invoiceid ?? listItem.id;
  return {
    ...listItem,
    invoiceid,
  };
}
