/**
 * WHMCS Subscriptions Provider - Mapper
 * 
 * Transforms raw WHMCS product/service data into normalized subscription types.
 */

import type { Subscription, SubscriptionStatus, SubscriptionCycle, SubscriptionList } from "../../contract";
import { subscriptionSchema, subscriptionListSchema, subscriptionStatusSchema } from "../../schema";
import {
  type WhmcsProductRaw,
  whmcsProductRawSchema,
  whmcsCustomFieldsContainerSchema,
  whmcsProductListResponseSchema,
} from "./raw.types";
import {
  parseAmount,
  formatDate,
  normalizeStatus,
  normalizeCycle,
} from "../../../providers/whmcs/utils";

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

export interface TransformSubscriptionListResponseOptions extends TransformSubscriptionOptions {
  status?: SubscriptionStatus | string;
  onItemError?: (error: unknown, product: WhmcsProductRaw) => void;
}

// Status mapping
const STATUS_MAP: Record<string, SubscriptionStatus> = {
  active: "Active",
  inactive: "Inactive",
  pending: "Pending",
  cancelled: "Cancelled",
  canceled: "Cancelled",
  terminated: "Terminated",
  completed: "Completed",
  suspended: "Suspended",
  fraud: "Cancelled",
};

// Cycle mapping
const CYCLE_MAP: Record<string, SubscriptionCycle> = {
  monthly: "Monthly",
  annually: "Annually",
  annual: "Annually",
  yearly: "Annually",
  quarterly: "Quarterly",
  "semi annually": "Semi-Annually",
  semiannually: "Semi-Annually",
  "semi-annually": "Semi-Annually",
  biennially: "Biennially",
  triennially: "Triennially",
  "one time": "One-time",
  onetime: "One-time",
  "one-time": "One-time",
  "one time fee": "One-time",
  free: "Free",
};

function mapStatus(status?: string | null): SubscriptionStatus {
  return normalizeStatus(status ?? undefined, STATUS_MAP, "Cancelled");
}

function mapCycle(cycle?: string | null): SubscriptionCycle {
  return normalizeCycle(cycle ?? undefined, CYCLE_MAP, "One-time");
}

function extractCustomFields(raw: unknown): Record<string, string> | undefined {
  if (!raw) return undefined;

  const container = whmcsCustomFieldsContainerSchema.safeParse(raw);
  if (!container.success) return undefined;

  const customfield = container.data.customfield;
  const fieldsArray = Array.isArray(customfield) ? customfield : [customfield];

  const entries = fieldsArray.reduce<Record<string, string>>((acc, field) => {
    if (field?.name && field.value) {
      acc[field.name] = field.value;
    }
    return acc;
  }, {});

  return Object.keys(entries).length > 0 ? entries : undefined;
}

/**
 * Transform raw WHMCS product/service into normalized Subscription
 */
export function transformWhmcsSubscription(
  rawProduct: unknown,
  options: TransformSubscriptionOptions = {}
): Subscription {
  // Validate raw data
  const product = whmcsProductRawSchema.parse(rawProduct);

  // Extract currency info
  const currency = product.pricing?.currency || options.defaultCurrencyCode || "JPY";
  const currencySymbol =
    product.pricing?.currencyprefix ||
    product.pricing?.currencysuffix ||
    options.defaultCurrencySymbol;

  // Determine amount
  const amount = parseAmount(
    product.amount ||
    product.recurringamount ||
    product.pricing?.amount ||
    product.firstpaymentamount ||
    0
  );

  // Transform to domain model
  const subscription: Subscription = {
    id: product.id,
    serviceId: product.serviceid || product.id,
    productName: product.name || product.translated_name || "Unknown Product",
    domain: product.domain || undefined,
    cycle: mapCycle(product.billingcycle),
    status: mapStatus(product.status),
    nextDue: formatDate(product.nextduedate || product.nextinvoicedate),
    amount,
    currency,
    currencySymbol,
    registrationDate: formatDate(product.regdate) || new Date().toISOString(),
    notes: product.notes || undefined,
    customFields: extractCustomFields(product.customfields),
    orderNumber: product.ordernumber || undefined,
    groupName: product.groupname || product.translated_groupname || undefined,
    paymentMethod: product.paymentmethodname || product.paymentmethod || undefined,
    serverName: product.servername || product.serverhostname || undefined,
  };

  // Validate against domain schema
  return subscriptionSchema.parse(subscription);
}

/**
 * Transform multiple WHMCS subscriptions
 */
export function transformWhmcsSubscriptions(
  rawProducts: unknown[],
  options: TransformSubscriptionOptions = {}
): Subscription[] {
  return rawProducts.map(raw => transformWhmcsSubscription(raw, options));
}

export function transformWhmcsSubscriptionListResponse(
  response: unknown,
  options: TransformSubscriptionListResponseOptions = {}
): SubscriptionList {
  const parsed = whmcsProductListResponseSchema.parse(response);
  const { status, onItemError, ...subscriptionOptions } = options;

  if (parsed.result === "error") {
    const message = parsed.message || "WHMCS GetClientsProducts returned error";
    throw new Error(message);
  }

  const productContainer = parsed.products?.product;
  const products = Array.isArray(productContainer)
    ? productContainer
    : productContainer
      ? [productContainer]
      : [];

  const subscriptions: Subscription[] = [];
  for (const product of products) {
    try {
      const subscription = transformWhmcsSubscription(product, subscriptionOptions);
      subscriptions.push(subscription);
    } catch (error) {
      onItemError?.(error, product);
    }
  }

  const totalResultsRaw = parsed.totalresults;
  const totalResults =
    typeof totalResultsRaw === "number"
      ? totalResultsRaw
      : typeof totalResultsRaw === "string"
        ? Number.parseInt(totalResultsRaw, 10)
        : subscriptions.length;

  if (status) {
    const normalizedStatus = subscriptionStatusSchema.parse(status);
    const filtered = subscriptions.filter(sub => sub.status === normalizedStatus);
    return subscriptionListSchema.parse({
      subscriptions: filtered,
      totalCount: filtered.length,
    });
  }

  return subscriptionListSchema.parse({
    subscriptions,
    totalCount: Number.isFinite(totalResults) ? totalResults : subscriptions.length,
  });
}

export function filterSubscriptionsByStatus(
  list: SubscriptionList,
  status: SubscriptionStatus | string
): SubscriptionList {
  const normalizedStatus = subscriptionStatusSchema.parse(status);
  const filtered = list.subscriptions.filter(sub => sub.status === normalizedStatus);
  return subscriptionListSchema.parse({
    subscriptions: filtered,
    totalCount: filtered.length,
  });
}
