/**
 * Orders Domain - Salesforce Provider Mapper
 *
 * Transforms Salesforce Order and OrderItem records into domain contracts.
 */

import type {
  OrderDetails,
  OrderItemDetails,
  OrderItemSummary,
  OrderSummary,
} from "../../contract";
import { normalizeBillingCycle } from "../../helpers";
import { orderDetailsSchema, orderSummarySchema, orderItemDetailsSchema } from "../../schema";
import type {
  SalesforceProduct2WithPricebookEntries,
  SalesforcePricebookEntryRecord,
} from "../../../catalog/providers/salesforce/raw.types";
import {
  defaultSalesforceOrderFieldMap,
  type SalesforceOrderFieldMap,
} from "./field-map";
import type {
  SalesforceOrderItemRecord,
  SalesforceOrderRecord,
} from "./raw.types";

/**
 * Helper function to get sort priority for item class
 */
function getItemClassSortPriority(itemClass?: string): number {
  if (!itemClass) return 4;
  const normalized = itemClass.toLowerCase();
  if (normalized === 'service') return 1;
  if (normalized === 'installation' || normalized === 'activation') return 2;
  if (normalized === 'add-on') return 3;
  return 4;
}

/**
 * Transform a Salesforce OrderItem record into domain details + summary.
 */
export function transformSalesforceOrderItem(
  record: SalesforceOrderItemRecord,
  fieldMap: SalesforceOrderFieldMap = defaultSalesforceOrderFieldMap
): { details: OrderItemDetails; summary: OrderItemSummary } {
  const pricebookEntry = (record.PricebookEntry ?? null) as
    | SalesforcePricebookEntryRecord
    | null;
  const product = pricebookEntry?.Product2 as SalesforceProduct2WithPricebookEntries | undefined;

  const orderItemFields = fieldMap.orderItem;
  const productFields = fieldMap.product;

  const billingCycleRaw =
    record[orderItemFields.billingCycle] ??
    (product ? (product[productFields.billingCycle] as unknown) : undefined);
  const billingCycle =
    billingCycleRaw !== undefined && billingCycleRaw !== null
      ? normalizeBillingCycle(billingCycleRaw)
      : undefined;

  const details = orderItemDetailsSchema.parse({
    id: record.Id,
    orderId: ensureString(record.OrderId) ?? "",
    quantity: normalizeQuantity(record.Quantity),
    unitPrice: coerceNumber(record.UnitPrice),
    totalPrice: coerceNumber(record.TotalPrice),
    billingCycle,
    product: product
      ? {
          id: ensureString(product.Id),
          name: ensureString(product.Name),
          sku: ensureString(product[productFields.sku]) ?? undefined,
          itemClass: ensureString(product[productFields.itemClass]) ?? undefined,
          whmcsProductId: resolveWhmcsProductId(product[productFields.whmcsProductId]),
          internetOfferingType:
            ensureString(product[productFields.internetOfferingType]) ?? undefined,
          internetPlanTier: ensureString(product[productFields.internetPlanTier]) ?? undefined,
          vpnRegion: ensureString(product[productFields.vpnRegion]) ?? undefined,
          isBundledAddon: coerceBoolean(product[productFields.isBundledAddon]),
          bundledAddonId: ensureString(product[productFields.bundledAddon]) ?? undefined,
        }
      : undefined,
  });

  return {
    details,
    summary: {
      productName: details.product?.name,
      name: details.product?.name,
      sku: details.product?.sku,
      productId: details.product?.id,
      status: undefined,
      billingCycle: details.billingCycle,
      itemClass: details.product?.itemClass,
      quantity: details.quantity,
      unitPrice: details.unitPrice,
      totalPrice: details.totalPrice,
      isBundledAddon: details.product?.isBundledAddon,
      bundledAddonId: details.product?.bundledAddonId,
    },
  };
}

/**
 * Transform a Salesforce Order record (with associated OrderItems) into domain OrderDetails.
 */
export function transformSalesforceOrderDetails(
  order: SalesforceOrderRecord,
  itemRecords: SalesforceOrderItemRecord[],
  fieldMap: SalesforceOrderFieldMap = defaultSalesforceOrderFieldMap
): OrderDetails {
  const transformedItems = itemRecords.map(record =>
    transformSalesforceOrderItem(record, fieldMap)
  );

  // Sort items by item class priority (Service -> Installation/Activation -> Add-on -> Others)
  transformedItems.sort((a, b) => {
    const priorityA = getItemClassSortPriority(a.summary.itemClass);
    const priorityB = getItemClassSortPriority(b.summary.itemClass);
    return priorityA - priorityB;
  });

  const items = transformedItems.map(item => item.details);
  const itemsSummary = transformedItems.map(item => item.summary);

  const summary = buildOrderSummary(order, itemsSummary, fieldMap);
  const orderFields = fieldMap.order;

  return orderDetailsSchema.parse({
    ...summary,
    accountId: ensureString(order.AccountId),
    accountName: ensureString(order.Account?.Name),
    pricebook2Id: ensureString(order.Pricebook2Id),
    activationType: ensureString(order[orderFields.activationType]),
    activationStatus: summary.activationStatus,
    activationScheduledAt: ensureString(order[orderFields.activationScheduledAt]),
    activationErrorCode: ensureString(order[orderFields.activationErrorCode]),
    activationErrorMessage: ensureString(order[orderFields.activationErrorMessage]),
    activatedDate: ensureString(order.ActivatedDate),
    items,
  });
}

/**
 * Transform a Salesforce Order record (with optional OrderItems) into domain OrderSummary.
 */
export function transformSalesforceOrderSummary(
  order: SalesforceOrderRecord,
  itemRecords: SalesforceOrderItemRecord[],
  fieldMap: SalesforceOrderFieldMap = defaultSalesforceOrderFieldMap
): OrderSummary {
  const transformedItems = itemRecords.map(record =>
    transformSalesforceOrderItem(record, fieldMap)
  );

  // Sort items by item class priority (Service -> Installation/Activation -> Add-on -> Others)
  transformedItems.sort((a, b) => {
    const priorityA = getItemClassSortPriority(a.summary.itemClass);
    const priorityB = getItemClassSortPriority(b.summary.itemClass);
    return priorityA - priorityB;
  });

  const itemsSummary = transformedItems.map(item => item.summary);
  return buildOrderSummary(order, itemsSummary, fieldMap);
}

function buildOrderSummary(
  order: SalesforceOrderRecord,
  itemsSummary: OrderItemSummary[],
  fieldMap: SalesforceOrderFieldMap
): OrderSummary {
  const orderFields = fieldMap.order;
  const effectiveDate =
    ensureString(order.EffectiveDate) ??
    ensureString(order.CreatedDate) ??
    new Date().toISOString();
  const createdDate = ensureString(order.CreatedDate) ?? effectiveDate;
  const lastModifiedDate = ensureString(order.LastModifiedDate) ?? createdDate;
  const totalAmount = coerceNumber(order.TotalAmount);

  return orderSummarySchema.parse({
    id: order.Id,
    orderNumber: ensureString(order.OrderNumber) ?? order.Id,
    status: ensureString(order.Status) ?? "Unknown",
    orderType: ensureString(order[orderFields.type]) ?? undefined,
    effectiveDate,
    totalAmount: typeof totalAmount === "number" ? totalAmount : undefined,
    createdDate,
    lastModifiedDate,
    whmcsOrderId: ensureString(order[orderFields.whmcsOrderId]) ?? undefined,
    activationStatus: ensureString(order[orderFields.activationStatus]) ?? undefined,
    itemsSummary,
  });
}

function ensureString(value: unknown): string | undefined {
  return typeof value === "string" ? value : undefined;
}

function coerceNumber(value: unknown): number | undefined {
  if (typeof value === "number") return Number.isFinite(value) ? value : undefined;
  if (typeof value === "string") {
    const parsed = Number.parseFloat(value);
    return Number.isFinite(parsed) ? parsed : undefined;
  }
  return undefined;
}

function normalizeQuantity(value: unknown): number {
  if (typeof value === "number" && Number.isFinite(value) && value > 0) {
    return Math.trunc(value);
  }
  return 1;
}

function resolveWhmcsProductId(value: unknown): string | undefined {
  if (value === null || value === undefined) {
    return undefined;
  }
  if (typeof value === "number") {
    return Number.isFinite(value) ? String(value) : undefined;
  }
  if (typeof value === "string") {
    return value;
  }
  return undefined;
}

function coerceBoolean(value: unknown): boolean | undefined {
  if (typeof value === "boolean") {
    return value;
  }
  return undefined;
}
