/**
 * Orders Domain - WHMCS Provider Mapper
 * 
 * Transforms normalized order data to WHMCS API format.
 */

import type { OrderDetails, OrderItemDetails } from "../../contract";
import { normalizeBillingCycle } from "../../helpers";
import {
  type WhmcsOrderItem,
  type WhmcsAddOrderParams,
  type WhmcsAddOrderPayload,
} from "./raw.types";

export interface OrderItemMappingResult {
  whmcsItems: WhmcsOrderItem[];
  summary: {
    totalItems: number;
    serviceItems: number;
    activationItems: number;
  };
}

/**
 * Map a single order item to WHMCS format
 */
export function mapOrderItemToWhmcs(
  item: OrderItemDetails,
  index = 0
): WhmcsOrderItem {
  if (!item.product?.whmcsProductId) {
    throw new Error(`Order item ${index} missing WHMCS product ID`);
  }

  const whmcsItem: WhmcsOrderItem = {
    productId: item.product.whmcsProductId,
    billingCycle: normalizeBillingCycle(item.billingCycle),
    quantity: item.quantity,
  };

  return whmcsItem;
}

/**
 * Map order details to WHMCS items format
 * Extracts items from OrderDetails and transforms to WHMCS API format
 */
export function mapOrderToWhmcsItems(
  orderDetails: OrderDetails
): OrderItemMappingResult {
  if (!orderDetails.items || orderDetails.items.length === 0) {
    throw new Error("No order items provided for WHMCS mapping");
  }

  const whmcsItems: WhmcsOrderItem[] = [];
  let serviceItems = 0;
  let activationItems = 0;

  orderDetails.items.forEach((item, index) => {
    const mapped = mapOrderItemToWhmcs(item, index);
    whmcsItems.push(mapped);
    
    if (mapped.billingCycle === "monthly") {
      serviceItems++;
    } else if (mapped.billingCycle === "onetime") {
      activationItems++;
    }
  });

  return {
    whmcsItems,
    summary: {
      totalItems: whmcsItems.length,
      serviceItems,
      activationItems,
    },
  };
}

/**
 * Build WHMCS AddOrder API payload from parameters
 * Converts structured params into WHMCS API array format
 * 
 * WHMCS AddOrder API Documentation:
 * @see https://developers.whmcs.com/api-reference/addorder/
 * 
 * Required Parameters:
 * - clientid (int): The client ID
 * - paymentmethod (string): Payment method (e.g. "stripe", "paypal", "mailin")
 * - pid (int[]): Array of product IDs
 * - qty (int[]): Array of product quantities (REQUIRED! Without this, no products are added)
 * - billingcycle (string[]): Array of billing cycles (e.g. "monthly", "onetime")
 * 
 * Optional Parameters:
 * - promocode (string): Promotion code to apply
 * - noinvoice (bool): Don't create invoice
 * - noinvoiceemail (bool): Don't send invoice email
 * - noemail (bool): Don't send order confirmation email
 * - configoptions (string[]): Base64 encoded serialized arrays of config options
 * - customfields (string[]): Base64 encoded serialized arrays of custom fields
 * 
 * Response Fields:
 * - result: "success" or "error"
 * - orderid: The created order ID
 * - serviceids: Comma-separated service IDs created
 * - addonids: Comma-separated addon IDs created
 * - domainids: Comma-separated domain IDs created
 * - invoiceid: The invoice ID created
 * 
 * Common Errors:
 * - "No items added to cart so order cannot proceed" - Missing or invalid qty parameter
 * - "Client ID Not Found" - Invalid client ID
 * - "Invalid Payment Method" - Payment method not recognized
 */
export function buildWhmcsAddOrderPayload(params: WhmcsAddOrderParams): WhmcsAddOrderPayload {
  const pids: string[] = [];
  const billingCycles: string[] = [];
  const quantities: number[] = [];
  const configOptions: string[] = [];
  const customFields: string[] = [];

  params.items.forEach(item => {
    pids.push(item.productId);
    billingCycles.push(item.billingCycle);
    quantities.push(item.quantity);

    // Handle config options - WHMCS expects base64 encoded serialized arrays
    configOptions.push(serializeForWhmcs(item.configOptions));

    // Handle custom fields - WHMCS expects base64 encoded serialized arrays
    customFields.push(serializeForWhmcs(item.customFields));
  });

  const payload: WhmcsAddOrderPayload = {
    clientid: params.clientId,
    paymentmethod: params.paymentMethod,
    pid: pids,
    billingcycle: billingCycles,
    qty: quantities,
  };

  // Add optional fields
  if (params.promoCode) {
    payload.promocode = params.promoCode;
  }
  if (params.noinvoice !== undefined) {
    payload.noinvoice = params.noinvoice;
  }
  if (params.noinvoiceemail !== undefined) {
    payload.noinvoiceemail = params.noinvoiceemail;
  }
  if (params.noemail !== undefined) {
    payload.noemail = params.noemail;
  }
  if (params.notes) {
    payload.notes = params.notes;
  }
  if (configOptions.some(opt => opt !== "")) {
    payload.configoptions = configOptions;
  }
  if (customFields.some(field => field !== "")) {
    payload.customfields = customFields;
  }

  return payload;
}

/**
 * Serialize object for WHMCS API
 * WHMCS expects base64-encoded serialized data
 */
function serializeForWhmcs(data?: Record<string, string>): string {
  if (!data || Object.keys(data).length === 0) {
    return "";
  }

  const entries = Object.entries(data).map(([key, value]) => {
    const safeKey = key ?? "";
    const safeValue = value ?? "";
    return (
      `s:${Buffer.byteLength(safeKey, "utf8")}:"${escapePhpString(safeKey)}";` +
      `s:${Buffer.byteLength(safeValue, "utf8")}:"${escapePhpString(safeValue)}";`
    );
  });

  const serialized = `a:${entries.length}:{${entries.join("")}}`;
  return Buffer.from(serialized).toString("base64");
}

function escapePhpString(value: string): string {
  return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
}

/**
 * Create order notes with Salesforce tracking information
 */
export function createOrderNotes(sfOrderId: string, additionalNotes?: string): string {
  const notes: string[] = [];

  // Always include Salesforce Order ID for tracking
  notes.push(`sfOrderId=${sfOrderId}`);

  // Add provisioning timestamp
  notes.push(`provisionedAt=${new Date().toISOString()}`);

  // Add additional notes if provided
  if (additionalNotes) {
    notes.push(additionalNotes);
  }

  return notes.join("; ");
}
