import type { Campaign } from '@/lib/types';

export type CampaignPreviewLine = {
  lineKey: string;
  materialId: string;
  quantity: number;
  unitPrice: number;
  currentDiscount: number;
};

export type CampaignLivePreviewResult = {
  discountByLineKey: Record<string, number>;
  totalCampaignDiscount: number;
};

type ComputeCampaignLivePreviewParams = {
  lines: CampaignPreviewLine[];
  campaigns: Campaign[];
  customerCategory?: string;
  atIso?: string;
  forPos?: boolean;
  isReturn?: boolean;
};

export function computeCampaignLivePreview(params: ComputeCampaignLivePreviewParams): CampaignLivePreviewResult {
  if (params.isReturn) {
    return { discountByLineKey: {}, totalCampaignDiscount: 0 };
  }

  const now = new Date(params.atIso || new Date().toISOString()).getTime();
  const scopeTag = String(params.customerCategory || 'general').trim().toLowerCase();

  const activeCampaigns = (params.campaigns || [])
    .filter((campaign) => {
      if (String(campaign?.status || 'inactive') !== 'active') return false;
      if (String(campaign?.type || 'multi_buy') !== 'multi_buy') return false;

      const start = new Date(String(campaign?.startDate || '')).getTime();
      const end = new Date(String(campaign?.endDate || '')).getTime();
      if (!Number.isNaN(start) && now < start) return false;
      if (!Number.isNaN(end) && now > end) return false;

      if (params.forPos && campaign?.autoApplyInPos === false) return false;

      const tags = Array.isArray(campaign?.customerTags)
        ? campaign.customerTags.map((value) => String(value || '').trim().toLowerCase()).filter(Boolean)
        : [];
      if (tags.length === 0 || tags.includes('all')) return true;
      return tags.includes(scopeTag);
    })
    .sort((a, b) => Number(b?.priority || 0) - Number(a?.priority || 0));

  if (activeCampaigns.length === 0) {
    return { discountByLineKey: {}, totalCampaignDiscount: 0 };
  }

  const lineByMaterialId = new Map<string, CampaignPreviewLine>();
  (params.lines || []).forEach((line) => {
    const materialId = String(line.materialId || '').trim();
    if (!materialId) return;
    lineByMaterialId.set(materialId, line);
  });

  const effectiveDiscountByLine = new Map<string, number>();
  (params.lines || []).forEach((line) => {
    const lineKey = String(line.lineKey || '').trim();
    if (!lineKey) return;
    effectiveDiscountByLine.set(lineKey, Math.max(0, Number(line.currentDiscount || 0)));
  });

  const discountByLineKey: Record<string, number> = {};
  let totalCampaignDiscount = 0;

  activeCampaigns.forEach((campaign) => {
    const campaignItems = Array.isArray(campaign?.items) ? campaign.items : [];
    const maxPerInvoice = Math.max(0, Number(campaign?.maxApplicationsPerInvoice || 0));
    const allowRepeats = campaign?.allowRepeats !== false;
    const allowStacking = campaign?.allowStacking === true;
    let usedPerInvoice = 0;

    campaignItems.forEach((campaignItem) => {
      const productId = String(campaignItem?.productId || '').trim();
      if (!productId) return;

      const line = lineByMaterialId.get(productId);
      if (!line) return;

      const lineKey = String(line.lineKey || '').trim();
      if (!lineKey) return;

      const qty = Math.max(0, Number(line.quantity || 0));
      const minQty = Math.max(1, Number(campaignItem?.minQty || 0));
      const bundlePrice = Math.max(0, Number(campaignItem?.bundlePrice || 0));
      if (qty < minQty || bundlePrice <= 0) return;

      let bundlesCount = Math.floor(qty / minQty);
      const maxApplicationsLine = Math.max(0, Number(campaignItem?.maxApplications || 0));
      if (maxApplicationsLine > 0) {
        bundlesCount = Math.min(bundlesCount, maxApplicationsLine);
      }
      if (maxPerInvoice > 0) {
        bundlesCount = Math.min(bundlesCount, Math.max(0, maxPerInvoice - usedPerInvoice));
      }
      if (!allowRepeats) {
        bundlesCount = Math.min(1, bundlesCount);
      }
      if (bundlesCount <= 0) return;

      const unitPrice = Math.max(0, Number(line.unitPrice || 0));
      const regularUnitPrice = Number.isFinite(Number(campaignItem?.regularUnitPrice))
        ? Number(campaignItem.regularUnitPrice)
        : unitPrice;
      const regularBundleTotal = regularUnitPrice * minQty;
      const discountPerBundle = Math.max(0, regularBundleTotal - bundlePrice);
      if (discountPerBundle <= 0) return;

      const lineSubtotal = Math.max(0, qty * unitPrice);
      const currentDiscount = Math.max(0, Number(effectiveDiscountByLine.get(lineKey) || 0));
      if (!allowStacking && currentDiscount > 0) return;

      const requestedDiscount = bundlesCount * discountPerBundle;
      const nextDiscount = Math.min(lineSubtotal, currentDiscount + requestedDiscount);
      const actualAppliedDiscount = Math.max(0, nextDiscount - currentDiscount);
      if (actualAppliedDiscount <= 0.0001) return;

      effectiveDiscountByLine.set(lineKey, nextDiscount);
      discountByLineKey[lineKey] = Number((Number(discountByLineKey[lineKey] || 0) + actualAppliedDiscount).toFixed(4));
      totalCampaignDiscount += actualAppliedDiscount;
      usedPerInvoice += bundlesCount;
    });
  });

  return {
    discountByLineKey,
    totalCampaignDiscount: Number(totalCampaignDiscount.toFixed(4)),
  };
}
