import { calculateDraft, reconcilePayroll, selectEffectiveRule } from "./logic.mjs";

const defaultMoney = new Intl.NumberFormat("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });

function addTextElement(document, parent, tagName, text, className = "") {
  const child = document.createElement(tagName);
  child.textContent = String(text);
  child.className = className;
  parent.append(child);
  return child;
}

export function renderEmployeeOptions(select, employees, selectedCode) {
  const document = select.ownerDocument;
  const options = employees.map((employee) => {
    const option = document.createElement("option");
    option.value = employee.employee_code;
    option.selected = employee.employee_code === selectedCode;
    option.textContent = `${employee.employee_code} · ${employee.name} · ${employee.role}`;
    return option;
  });
  select.replaceChildren(...options);
}

export function renderDraft(container, statusElement, draft, employee, money = defaultMoney) {
  const document = container.ownerDocument;
  statusElement.textContent = draft.status === "draft" ? "READY FOR HUMAN REVIEW" : "BLOCKED";
  statusElement.className = `status ${draft.status}`;

  if (draft.status === "blocked") {
    const card = document.createElement("div");
    card.className = "exception-card";
    addTextElement(document, card, "h3", `${employee.employee_code} · calculation blocked`);
    const list = document.createElement("ul");
    for (const item of draft.exceptions) {
      const listItem = document.createElement("li");
      addTextElement(document, listItem, "strong", item.code);
      addTextElement(document, listItem, "span", ` · ${item.message}`);
      list.append(listItem);
    }
    card.append(list);
    container.replaceChildren(card);
    return;
  }

  const title = document.createElement("div");
  title.className = "payslip-title";
  const employeeBlock = document.createElement("div");
  addTextElement(document, employeeBlock, "span", "Synthetic employee");
  addTextElement(document, employeeBlock, "strong", `${employee.employee_code} · ${employee.name}`);
  const ruleBlock = document.createElement("div");
  addTextElement(document, ruleBlock, "span", "Rule");
  addTextElement(document, ruleBlock, "strong", draft.rule_id);
  title.append(employeeBlock, ruleBlock);

  const grid = document.createElement("dl");
  grid.className = "payslip-grid";
  const figures = [
    ["Gross pay", money.format(draft.gross_pay), ""],
    ["Estimated SSO", `(${money.format(draft.sso_employee)})`, ""],
    ["Estimated PIT", `(${money.format(draft.estimated_withholding_tax)})`, ""],
    ["Other deductions", `(${money.format(draft.employee_deductions)})`, ""],
    ["Draft net pay", money.format(draft.net_pay), "net"],
  ];
  for (const [label, amount, className] of figures) {
    const item = document.createElement("div");
    item.className = className;
    addTextElement(document, item, "dt", label);
    addTextElement(document, item, "dd", amount);
    grid.append(item);
  }

  const note = document.createElement("p");
  note.className = "preview-note";
  note.textContent = `DRAFT · TRAINING ONLY · Taxable annual estimate ${money.format(draft.taxable_annual)} · Annual PIT estimate ${money.format(draft.estimated_annual_tax)}`;
  container.replaceChildren(title, grid, note);
}

export function csvCell(input) {
  const raw = String(input ?? "");
  const text = typeof input === "string" && /^[=+\-@]/.test(raw) ? `'${raw}` : raw;
  return /[",\n\r]/.test(text) ? `"${text.replaceAll('"', '""')}"` : text;
}

function initializePayrollApp(document) {
  const element = (id) => document.querySelector(`#${id}`);
  const rulesPayload = JSON.parse(element("payroll-rules").textContent);
  const goldenCases = JSON.parse(element("golden-cases").textContent);
  const warning = element("training-warning").textContent.trim();
  const employees = [
    { employee_code: "TRN-001", name: "Aree", role: "Training Coordinator", class: "regular-monthly", province: "Bangkok", base_salary: 50000 },
    { employee_code: "TRN-002", name: "Krit", role: "Workshop Planner", class: "regular-monthly", province: "Bangkok", base_salary: 35000 },
    { employee_code: "TRN-003", name: "Mali", role: "Learning Analyst", class: "regular-monthly", province: "Bangkok", base_salary: 62000 },
  ];
  const drafts = [];
  const value = (id) => Number(element(id).value || 0);

  function syncEmployeeSalary() {
    const employee = employees.find((item) => item.employee_code === element("employee-select").value);
    if (employee) element("base-salary").value = employee.base_salary;
  }

  function showEmployeeOptions(selectedCode) {
    renderEmployeeOptions(element("employee-select"), employees, selectedCode);
    syncEmployeeSalary();
  }

  function currentEmployee() {
    return employees.find((item) => item.employee_code === element("employee-select").value);
  }

  function calculate() {
    const employee = currentEmployee();
    const payDate = element("pay-date").value;
    const rule = selectEffectiveRule(rulesPayload.rules, payDate, employee.province, employee.class);
    const draft = calculateDraft(employee, {
      pay_date: payDate,
      base_salary: value("base-salary"),
      commission: value("commission"),
      commission_evidence_id: element("commission-evidence").value.trim(),
      allowance: value("allowance"),
      allowance_evidence_id: element("allowance-evidence").value.trim(),
      employee_deductions: value("deductions"),
      employee_deductions_evidence_id: element("deductions-evidence").value.trim(),
      ytd_gross_earnings: 0,
      ytd_withheld: 0,
      remaining_periods: value("remaining-periods"),
    }, rule);
    drafts.push({ ...draft, employee_name: employee.name, pay_date: payDate });
    renderDraft(element("payslip-preview"), element("draft-status"), draft, employee);
  }

  function downloadCsv(name, rows) {
    const csv = rows.map((row) => row.map(csvCell).join(",")).join("\n") + "\n";
    const url = URL.createObjectURL(new Blob([csv], { type: "text/csv;charset=utf-8" }));
    const anchor = document.createElement("a");
    anchor.href = url;
    anchor.download = name;
    anchor.click();
    URL.revokeObjectURL(url);
  }

  function summaryRows() {
    const reconciliation = reconcilePayroll(drafts);
    return [
      ["DRAFT · TRAINING ONLY"],
      [warning],
      ["golden_case_count", goldenCases.length],
      ["reconciliation_status", reconciliation.status],
      ["employee_code", "employee_name", "pay_date", "status", "gross_pay", "sso_employee", "estimated_withholding_tax", "total_deductions", "net_pay", "rule_id"],
      ...drafts.map((draft) => [draft.employee_code, draft.employee_name, draft.pay_date, draft.status, draft.gross_pay ?? "", draft.sso_employee ?? "", draft.estimated_withholding_tax ?? "", draft.total_deductions ?? "", draft.net_pay ?? "", draft.rule_id ?? ""]),
    ];
  }

  function exceptionRows() {
    return [
      ["DRAFT · TRAINING ONLY"],
      [warning],
      ["employee_code", "pay_date", "exception_code", "message"],
      ...drafts.flatMap((draft) => draft.exceptions.map((item) => [draft.employee_code, draft.pay_date, item.code, item.message])),
    ];
  }

  function addSyntheticEmployee() {
    const code = element("new-code").value.trim();
    const name = element("new-name").value.trim();
    const role = element("new-role").value.trim();
    if (!code || !name || !role || employees.some((employee) => employee.employee_code === code)) return;
    employees.push({ employee_code: code, name, role, class: "regular-monthly", province: "Bangkok", base_salary: 30000 });
    showEmployeeOptions(code);
  }

  element("employee-select").addEventListener("change", syncEmployeeSalary);
  element("add-employee").addEventListener("click", addSyntheticEmployee);
  element("calculate-draft").addEventListener("click", calculate);
  element("print-draft").addEventListener("click", () => window.print());
  element("download-summary").addEventListener("click", () => downloadCsv("payroll-summary-draft-training-only.csv", summaryRows()));
  element("download-exceptions").addEventListener("click", () => downloadCsv("payroll-exception-log-draft-training-only.csv", exceptionRows()));
  showEmployeeOptions("TRN-001");
}

if (typeof document !== "undefined") initializePayrollApp(document);
