/**
 * آینهٔ سمت‌کلاینتِ `BillingCalculator` سرور. تنها منبع محاسبهٔ سهم‌ها در پنل است —
 * هیچ صفحه‌ای نباید فرمول درصدی جداگانه بنویسد، وگرنه مبلغِ نمایش‌داده‌شده با مبلغِ
 * ثبت‌شده واگرا می‌شود.
 */

export interface CoverageRule {
  covered: boolean;
  percent: number;
  /** درصد سهم اجباری بیمار از مبلغ تحت پوشش؛ فقط در بیمهٔ تکمیلی معنا دارد. */
  franchise: number;
  ceiling: number | null;
}

/** قراردادِ بیمهٔ tenant، همان شکلی که `/api/v1/billing/tenant-insurances` می‌دهد. */
export interface TenantContract {
  insurance_id: number;
  insurance_name: string | null;
  insurance_kind: string | null;
  is_active?: boolean;
  coverage_percent: number;
  franchise_percent: number;
  annual_ceiling_rials: number | null;
  category_coverages?: Record<string, number>;
}

/** ویزیت آیتم سرویس نیست؛ نوعِ پیش‌فرضش سرپایی است. */
export const DEFAULT_SERVICE_CATEGORY = 'outpatient';

/** سهم بیمهٔ پایه از کل مبلغ یک ردیف (با سقف تعهد). */
export function baseShareOf(total: number, base: CoverageRule | null): number {
  if (!base || !base.covered) return 0;

  const share = Math.round(total * (base.percent / 100));

  return base.ceiling !== null ? Math.min(share, base.ceiling) : share;
}

/**
 * سهم بیمار یک ردیف: کل − سهم پایه (با سقف) − سهم تکمیلی. محاسبه زنجیره‌ای است؛
 * تکمیلی روی باقیماندهٔ بعد از پایه کار می‌کند، نه روی کل مبلغ. فرانشیزِ تکمیلی
 * درصدی از همان باقیمانده است و از سهم تکمیلی کسر می‌شود، نه اینکه روی سهم بیمار
 * سوار شود؛ فرانشیزِ بیمهٔ پایه در محاسبه دخالت نمی‌کند.
 */
export function patientShareOf(total: number, base: CoverageRule | null, supp: CoverageRule | null): number {
  const baseShare = baseShareOf(total, base);
  const remaining = total - baseShare;

  let suppShare = 0;
  if (supp && supp.covered) {
    suppShare = Math.max(
      0,
      Math.round(remaining * (supp.percent / 100)) - Math.round(remaining * (supp.franchise / 100)),
    );
    if (supp.ceiling !== null) suppShare = Math.min(suppShare, supp.ceiling);
  }

  return total - baseShare - suppShare;
}

/** درصد مؤثر قرارداد برای یک نوع خدمت؛ نبودِ ردیف → ستون قدیمی قرارداد. */
export function contractPercentFor(contract: TenantContract, category: string): number {
  return Number(contract.category_coverages?.[category] ?? contract.coverage_percent ?? 0);
}

/** قاعدهٔ پوشش یک ردیف تحت یک قرارداد. فرانشیز فقط از قرارداد تکمیلی خوانده می‌شود. */
export function ruleOf(contract: TenantContract | null, category: string): CoverageRule | null {
  if (!contract) return null;

  return {
    covered: true,
    percent: contractPercentFor(contract, category),
    franchise: contract.insurance_kind === 'supplementary' ? contract.franchise_percent : 0,
    ceiling: contract.annual_ceiling_rials,
  };
}

export interface BillableLine {
  /** مبلغ کل ردیف (با احتساب تعداد). */
  total: number;
  /** نوع خدمت؛ برای ویزیت نوعِ انتخاب‌شدهٔ مراجعه. */
  category: string;
  /** خدمتی که پوشش بیمه ندارد کامل سهم بیمار است. */
  insured: boolean;
}

export interface ShareBreakdown {
  total: number;
  /** مجموع سهم هر دو بیمه — برای نمایشِ یک‌خطی. */
  insurance: number;
  base: number;
  supplementary: number;
  patient: number;
}

/**
 * تفکیک سهم برای مجموعه‌ای از ردیف‌ها تحت قرارداد پایه و (اختیاری) تکمیلی.
 * محاسبه زنجیره‌ای است: پایه روی کل، تکمیلی روی باقیماندهٔ بعد از پایه.
 */
export function breakdownOf(
  lines: BillableLine[],
  base: TenantContract | null,
  supplementary: TenantContract | null = null,
): ShareBreakdown {
  return lines.reduce<ShareBreakdown>((acc, line) => {
    const baseRule = line.insured ? ruleOf(base, line.category) : null;
    const suppRule = line.insured ? ruleOf(supplementary, line.category) : null;

    const patient   = line.insured ? patientShareOf(line.total, baseRule, suppRule) : line.total;
    const baseShare = baseShareOf(line.total, baseRule);

    return {
      total:         acc.total + line.total,
      base:          acc.base + baseShare,
      supplementary: acc.supplementary + (line.total - patient - baseShare),
      insurance:     acc.insurance + (line.total - patient),
      patient:       acc.patient + patient,
    };
  }, { total: 0, base: 0, supplementary: 0, insurance: 0, patient: 0 });
}
