const roundAmount = (value) => Number(Number(value || 0).toFixed(2));

const MONTH_LABELS = [
  "Janvier",
  "Fevrier",
  "Mars",
  "Avril",
  "Mai",
  "Juin",
  "Juillet",
  "Aout",
  "Septembre",
  "Octobre",
  "Novembre",
  "Decembre",
];

export const G50TER_QUARTERS = [
  {
    trimestre: 1,
    label: "1er trimestre",
    months: [1, 2, 3],
    deadlineMonth: 4,
    deadlineYearOffset: 0,
    deadlineLabel: "20 Avril",
  },
  {
    trimestre: 2,
    label: "2eme trimestre",
    months: [4, 5, 6],
    deadlineMonth: 7,
    deadlineYearOffset: 0,
    deadlineLabel: "20 Juillet",
  },
  {
    trimestre: 3,
    label: "3eme trimestre",
    months: [7, 8, 9],
    deadlineMonth: 10,
    deadlineYearOffset: 0,
    deadlineLabel: "20 Octobre",
  },
  {
    trimestre: 4,
    label: "4eme trimestre",
    months: [10, 11, 12],
    deadlineMonth: 1,
    deadlineYearOffset: 1,
    deadlineLabel: "20 Janvier N+1",
  },
];

const PROFESSIONAL_EXPENSE_MIN = 1000;
const PROFESSIONAL_EXPENSE_MAX = 1500;
const ANNUAL_IRG_BRACKETS = [
  { from: 0, to: 240000, rate: 0 },
  { from: 240000, to: 480000, rate: 0.23 },
  { from: 480000, to: 960000, rate: 0.27 },
  { from: 960000, to: 1920000, rate: 0.3 },
  { from: 1920000, to: 3840000, rate: 0.33 },
  { from: 3840000, to: Infinity, rate: 0.35 },
];

export const deriveFiscalDeclarationYear = (fiscalYear) => {
  if (!fiscalYear) {
    return new Date().getUTCFullYear();
  }

  if (fiscalYear.label && /^\d{4}$/.test(String(fiscalYear.label))) {
    return Number(fiscalYear.label);
  }

  if (fiscalYear.start_date) {
    return Number(String(fiscalYear.start_date).slice(0, 4));
  }

  if (fiscalYear.end_date) {
    return Number(String(fiscalYear.end_date).slice(0, 4));
  }

  return new Date().getUTCFullYear();
};

export const getQuarterFromDate = (value = new Date()) => {
  const date = value instanceof Date ? value : new Date(value);

  if (Number.isNaN(date.getTime())) {
    return 1;
  }

  return Math.floor(date.getUTCMonth() / 3) + 1;
};

export const buildG50terQuarterMeta = (annee, trimestre) => {
  const quarter = G50TER_QUARTERS.find((item) => item.trimestre === Number(trimestre)) || G50TER_QUARTERS[0];
  const deadlineYear = Number(annee) + quarter.deadlineYearOffset;
  const deadlineDate = `${String(deadlineYear)}-${String(quarter.deadlineMonth).padStart(2, "0")}-20`;

  return {
    ...quarter,
    annee: Number(annee),
    months_label: quarter.months.map((month) => MONTH_LABELS[month - 1]).join(", "),
    periode_label: quarter.months.map((month) => MONTH_LABELS[month - 1]).join(", "),
    deadline_date: deadlineDate,
    deadline_label:
      quarter.trimestre === 4
        ? `20 Janvier ${Number(annee) + 1}`
        : `20 ${MONTH_LABELS[quarter.deadlineMonth - 1]}`,
  };
};

export const getDeadlineState = ({ statut, deadlineDate, today = new Date() }) => {
  if (statut === "deposee" || statut === "validee") {
    return "filed";
  }

  const deadline = new Date(`${deadlineDate}T00:00:00Z`);
  const reference = today instanceof Date ? today : new Date(today);
  const diffDays = Math.ceil((deadline.getTime() - reference.getTime()) / (1000 * 60 * 60 * 24));

  if (diffDays < 0) {
    return "overdue";
  }

  if (diffDays < 7) {
    return "due_soon";
  }

  return "upcoming";
};

export const ensureG50terDeclarations = async (db, { companyId, fiscalYear, userId = null }) => {
  const annee = deriveFiscalDeclarationYear(fiscalYear);
  const rows = [];

  for (const quarter of G50TER_QUARTERS) {
    const meta = buildG50terQuarterMeta(annee, quarter.trimestre);
    const result = await db.query(
      `
        INSERT INTO g50ter_declarations (
          company_id,
          fiscal_year_id,
          trimestre,
          annee,
          delai_limite,
          created_by
        )
        VALUES ($1, $2, $3, $4, $5, $6)
        ON CONFLICT (company_id, annee, trimestre)
        DO UPDATE SET
          fiscal_year_id = EXCLUDED.fiscal_year_id,
          delai_limite = EXCLUDED.delai_limite,
          updated_at = CURRENT_TIMESTAMP
        RETURNING id, trimestre, annee
      `,
      [companyId, fiscalYear.id, quarter.trimestre, annee, meta.deadline_date, userId],
    );

    if (result.rows[0]) {
      rows.push(result.rows[0]);
    }
  }

  return rows;
};

const computeAnnualIrg = (annualTaxableIncome) => {
  const breakdown = [];
  let annualTax = 0;

  for (const bracket of ANNUAL_IRG_BRACKETS) {
    const taxableInBracket = Math.max(
      Math.min(annualTaxableIncome, bracket.to) - bracket.from,
      0,
    );

    if (taxableInBracket <= 0) {
      continue;
    }

    const bracketTax = roundAmount(taxableInBracket * bracket.rate);
    annualTax = roundAmount(annualTax + bracketTax);
    breakdown.push({
      from: bracket.from,
      to: Number.isFinite(bracket.to) ? bracket.to : null,
      taxable_amount: roundAmount(taxableInBracket),
      rate: roundAmount(bracket.rate * 100),
      tax_amount: bracketTax,
    });
  }

  return {
    annualTax,
    breakdown,
  };
};

export const calculateIrgBareme = ({ salaireBrut, nbMois = 1 }) => {
  const monthsCount = Math.max(Number.parseInt(nbMois, 10) || 1, 1);
  const gross = roundAmount(Number(salaireBrut || 0));

  if (!Number.isFinite(gross) || gross < 0) {
    throw new Error("Le salaire brut est invalide.");
  }

  const monthlyGross = roundAmount(gross / monthsCount);

  if (monthlyGross <= 30000) {
    return {
      salaire_brut: gross,
      nb_mois: monthsCount,
      salaire_mensuel_moyen: monthlyGross,
      frais_professionnels_mensuels: 0,
      salaire_imposable_mensuel: monthlyGross,
      revenu_imposable_annuel: roundAmount(monthlyGross * 12),
      irg_annuel: 0,
      irg_mensuel: 0,
      montant_irg: 0,
      bareme: [],
      note:
        "Simulation indicatrice: le salaire mensuel moyen n'excede pas 30 000 DA, l'IRG est nul.",
    };
  }

  const professionalExpenseMonthly = roundAmount(
    Math.min(
      Math.max(monthlyGross * 0.4, PROFESSIONAL_EXPENSE_MIN),
      PROFESSIONAL_EXPENSE_MAX,
    ),
  );
  const monthlyTaxable = roundAmount(
    Math.max(monthlyGross - professionalExpenseMonthly, 0),
  );
  const annualTaxable = roundAmount(monthlyTaxable * 12);
  const { annualTax, breakdown } = computeAnnualIrg(annualTaxable);
  const monthlyIrg = roundAmount(annualTax / 12);
  const totalIrg = roundAmount(monthlyIrg * monthsCount);

  return {
    salaire_brut: gross,
    nb_mois: monthsCount,
    salaire_mensuel_moyen: monthlyGross,
    frais_professionnels_mensuels: professionalExpenseMonthly,
    salaire_imposable_mensuel: monthlyTaxable,
    revenu_imposable_annuel: annualTaxable,
    irg_annuel: annualTax,
    irg_mensuel: monthlyIrg,
    montant_irg: totalIrg,
    bareme: breakdown,
    note:
      "Simulation indicatrice fondee sur un bareme progressif annualise avec abattement professionnel standard.",
  };
};
