/* CA Automator — Tax Advisory engines (JS mirror of
   server/tax_advisory_engines.py). Kept numerically identical to the Python
   engine — every change here must be made there too, and vice versa. */
(function (global) {
  'use strict';

  const R2 = x => Math.round((Number(x) || 0) * 100) / 100;
  const N = (v, dflt) => (v === null || v === undefined || v === '') ? (dflt || 0) : (isFinite(Number(v)) ? Number(v) : (dflt || 0));

  function salesVatReconciliation(lines, returnOutputVat) {
    const rows = []; let totalTaxable = 0, totalOutput = 0;
    (lines || []).forEach(r => {
      const taxable = N(r.taxable_sales), outputVat = N(r.output_vat), declared = !!r.declared_in_return;
      totalTaxable += taxable; totalOutput += outputVat;
      rows.push({ id: r.id, period_label: r.period_label || '', invoice_no: r.invoice_no || '', party: r.party || '',
        taxable_sales: R2(taxable), output_vat: R2(outputVat), declared_in_return: declared });
    });
    const undeclared = rows.filter(r => !r.declared_in_return);
    const undeclaredVat = undeclared.reduce((s, r) => s + r.output_vat, 0);
    const out = { rows, total_taxable_sales: R2(totalTaxable), total_output_vat: R2(totalOutput),
      undeclared_count: undeclared.length, undeclared_output_vat: R2(undeclaredVat) };
    if (returnOutputVat !== null && returnOutputVat !== undefined && returnOutputVat !== '') {
      const rov = N(returnOutputVat);
      out.return_output_vat = R2(rov);
      out.variance_vs_return = R2(totalOutput - rov);
    }
    return out;
  }

  function purchaseVatReconciliation(lines, returnInputVat) {
    const rows = []; let totalTaxable = 0, totalInput = 0, totalEligibleInput = 0;
    (lines || []).forEach(r => {
      const taxable = N(r.taxable_purchase), inputVat = N(r.input_vat);
      const eligible = r.eligible === undefined ? true : !!r.eligible;
      const matched = !!r.matched_with_supplier;
      totalTaxable += taxable; totalInput += inputVat;
      if (eligible) totalEligibleInput += inputVat;
      rows.push({ id: r.id, period_label: r.period_label || '', invoice_no: r.invoice_no || '', party: r.party || '',
        taxable_purchase: R2(taxable), input_vat: R2(inputVat), eligible, ineligibility_reason: r.ineligibility_reason || '',
        matched_with_supplier: matched });
    });
    const ineligibleRows = rows.filter(r => !r.eligible);
    const unmatchedRows = rows.filter(r => !r.matched_with_supplier);
    const out = { rows, total_taxable_purchase: R2(totalTaxable), total_input_vat: R2(totalInput),
      total_eligible_input_vat: R2(totalEligibleInput), ineligible_count: ineligibleRows.length,
      ineligible_input_vat: R2(ineligibleRows.reduce((s, r) => s + r.input_vat, 0)),
      unmatched_count: unmatchedRows.length, unmatched_input_vat: R2(unmatchedRows.reduce((s, r) => s + r.input_vat, 0)) };
    if (returnInputVat !== null && returnInputVat !== undefined && returnInputVat !== '') {
      const riv = N(returnInputVat);
      out.return_input_vat = R2(riv);
      out.variance_vs_return = R2(totalEligibleInput - riv);
    }
    return out;
  }

  function tdsReconciliation(lines) {
    const rows = (lines || []).map(r => {
      const deducted = N(r.tds_deducted), deposited = N(r.tds_deposited);
      const variance = deposited - deducted;
      return { id: r.id, fy_label: r.fy_label || '', section: r.section || '', payee: r.payee || '',
        base_amount: R2(N(r.base_amount)), tds_deducted: R2(deducted), tds_deposited: R2(deposited),
        variance: R2(variance), return_filed: !!r.return_filed, fully_deposited: variance >= -0.005 };
    });
    const notDeposited = rows.filter(r => !r.fully_deposited);
    const notFiled = rows.filter(r => !r.return_filed);
    const totalDeducted = rows.reduce((s, r) => s + r.tds_deducted, 0);
    const totalDeposited = rows.reduce((s, r) => s + r.tds_deposited, 0);
    return { rows, total_deducted: R2(totalDeducted), total_deposited: R2(totalDeposited),
      total_variance: R2(totalDeposited - totalDeducted), short_deposited_count: notDeposited.length, not_filed_count: notFiled.length };
  }

  function deferredTaxProvision(lines, taxRatePct) {
    const rate = N(taxRatePct) / 100;
    let netDiff = 0;
    const rows = (lines || []).map(r => {
      const book = N(r.book_value), tax = N(r.tax_value);
      const diff = book - tax;
      netDiff += diff;
      return { id: r.id, particular: r.particular || '', book_value: R2(book), tax_value: R2(tax),
        temporary_difference: R2(diff), deferred_tax: R2(diff * rate) };
    });
    const netDeferredTax = netDiff * rate;
    return { rows, tax_rate_pct: N(taxRatePct), net_temporary_difference: R2(netDiff), net_deferred_tax: R2(Math.abs(netDeferredTax)),
      classification: netDeferredTax > 0 ? 'Net deferred tax liability' : (netDeferredTax < 0 ? 'Net deferred tax asset' : 'Nil') };
  }

  function minimumTaxCheck(computedTaxLiability, turnover, minimumTaxPct) {
    const liability = N(computedTaxLiability);
    const turnoverV = N(turnover);
    if (minimumTaxPct === null || minimumTaxPct === undefined || minimumTaxPct === '') {
      return { computed_tax_liability: R2(liability), turnover: R2(turnoverV), minimum_tax_pct: null,
        minimum_tax_amount: null, shortfall: null, minimum_tax_binding: null,
        note: 'No minimum-tax percentage has been entered — confirm the currently-applicable figure before relying on this check.' };
    }
    const pctV = N(minimumTaxPct);
    const floor = turnoverV * pctV / 100;
    const shortfall = Math.max(0, floor - liability);
    return { computed_tax_liability: R2(liability), turnover: R2(turnoverV), minimum_tax_pct: pctV,
      minimum_tax_amount: R2(floor), shortfall: R2(shortfall), minimum_tax_binding: shortfall > 0 };
  }

  function peRiskAssessment(factors) {
    const severityRank = { Low: 1, Medium: 2, High: 3 };
    let highest = 0, presentCount = 0;
    const rows = (factors || []).map(f => {
      const present = !!f.present;
      const level = f.risk_level || 'Low';
      if (present) { presentCount++; highest = Math.max(highest, severityRank[level] || 1); }
      return { id: f.id, factor: f.factor || '', present, details: f.details || '', risk_level: level };
    });
    const overall = { 3: 'High', 2: 'Medium', 1: 'Low', 0: 'None' }[highest];
    return { factors: rows, present_count: presentCount, overall_risk: overall };
  }

  global.TaxAdvisoryEngines = {
    R2, salesVatReconciliation, purchaseVatReconciliation, tdsReconciliation,
    deferredTaxProvision, minimumTaxCheck, peRiskAssessment,
  };
})(window);
