"use client";

import { NEXT_PUBLIC_API_URL } from "@/config/api";
import { clientAuthFetch } from "@/app/utils/clientAuthFetch";
import {
  exportChartToXlsx,
  exportMultiSheetToXlsx,
} from "@/app/(main)/chart/_components/exportChartToXlsx";

export interface GrnReportRow {
  poCode?: string;
  deliveryNoteNo?: string;
  receiptDate?: string;
  itemCode?: string;
  itemName?: string;
  acceptedQty?: number;
  receivedQty?: number;
  demandQty?: number;
  uom?: string;
  purchaseUomDesc?: string;
  stockUomDesc?: string;
  productLotNo?: string;
  expiryDate?: string;
  supplierCode?: string;
  supplier?: string;
  status?: string;
  /** PO line unit price (purchase_order_line.up) */
  unitPrice?: number;
  /** unitPrice × acceptedQty */
  lineAmount?: number;
  /** PO currency code (currency.code) */
  currencyCode?: string;
  /** M18 AN document code from m18_goods_receipt_note_log.grn_code */
  grnCode?: string;
  /** M18 record id (m18_record_id) */
  grnId?: number | string;
  /** From purchase_order.m18CreatedUId; e.g. "2569 (legato)" */
  poM18CreatorDisplay?: string;
  [key: string]: unknown;
}

/** Sheet "已上架PO金額": totals grouped by receipt date + currency / PO (ADMIN-only data from API). */
export interface ListedPoAmounts {
  currencyTotals: {
    receiptDate?: string;
    currencyCode?: string;
    totalAmount?: number;
  }[];
  byPurchaseOrder: {
    receiptDate?: string;
    poCode?: string;
    currencyCode?: string;
    totalAmount?: number;
    grnCodes?: string;
  }[];
}

export interface GrnReportResponse {
  rows: GrnReportRow[];
  listedPoAmounts?: ListedPoAmounts;
}

/**
 * Fetch GRN (Goods Received Note) report data by date range.
 * Backend: GET /report/grn-report?receiptDateStart=&receiptDateEnd=&itemCode=
 */
export async function fetchGrnReportData(
  criteria: Record<string, string>
): Promise<{ rows: GrnReportRow[]; listedPoAmounts?: ListedPoAmounts }> {
  const queryParams = new URLSearchParams(criteria).toString();
  const url = `${NEXT_PUBLIC_API_URL}/report/grn-report?${queryParams}`;

  const response = await clientAuthFetch(url, {
    method: "GET",
    headers: { Accept: "application/json" },
  });

  if (response.status === 401 || response.status === 403)
    throw new Error("Unauthorized");
  if (!response.ok)
    throw new Error(`HTTP error! status: ${response.status}`);

  const data = (await response.json()) as GrnReportResponse | GrnReportRow[];
  if (Array.isArray(data)) {
    return { rows: data };
  }
  const body = data as GrnReportResponse;
  return {
    rows: body.rows ?? [],
    listedPoAmounts: body.listedPoAmounts,
  };
}

/** Coerce API JSON (number or numeric string) to a finite number. */
function coerceToFiniteNumber(value: unknown): number | null {
  if (value === null || value === undefined) return null;
  if (typeof value === "number" && Number.isFinite(value)) return value;
  if (typeof value === "string") {
    const t = value.trim();
    if (t === "") return null;
    const n = Number(t);
    return Number.isFinite(n) ? n : null;
  }
  return null;
}

/**
 * Cell value for money columns: numeric when possible so Excel export can apply `#,##0.00` (see exportChartToXlsx).
 */
function moneyCellValue(v: unknown): number | string {
  const n = coerceToFiniteNumber(v);
  if (n === null) return "";
  return n;
}

/** Thousands separator for quantities (up to 4 decimal places, trims trailing zeros). */
const formatQty = (n: number | undefined | null): string => {
  if (n === undefined || n === null || Number.isNaN(Number(n))) return "";
  return new Intl.NumberFormat("en-US", {
    minimumFractionDigits: 0,
    maximumFractionDigits: 4,
  }).format(Number(n));
};

/** Excel column headers (bilingual) for GRN report */
function toExcelRow(
  r: GrnReportRow,
  includeFinancialColumns: boolean
): Record<string, string | number | undefined> {
  const base: Record<string, string | number | undefined> = {
    "PO No. / 訂單編號": r.poCode ?? "",
    "Delivery Note No. / 送貨單編號": r.deliveryNoteNo ?? "",
    "Receipt Date / 收貨日期": r.receiptDate ?? "",
    "Item Code / 物料編號": r.itemCode ?? "",
    "Item Name / 物料名稱": r.itemName ?? "",
    "Qty / 數量": formatQty(
      r.acceptedQty ?? r.receivedQty ?? undefined
    ),
    "Demand Qty / 訂單數量": formatQty(r.demandQty),
    "UOM / 單位": r.uom ?? r.purchaseUomDesc ?? r.stockUomDesc ?? "",
    "Supplier Lot No. 供應商批次": r.productLotNo ?? "",
    "Expiry Date / 到期日": r.expiryDate ?? "",
    "Supplier Code / 供應商編號": r.supplierCode ?? "",
    "Supplier / 供應商": r.supplier ?? "",
    "入倉狀態": r.status ?? "",
  };
  if (includeFinancialColumns) {
    base["Unit Price / 單價"] = moneyCellValue(r.unitPrice);
    base["Currency / 貨幣"] = r.currencyCode ?? "";
    base["Amount / 金額"] = moneyCellValue(r.lineAmount);
  }
  base["GRN Code / M18 入倉單號"] = r.grnCode ?? "";
  base["GRN Id / M18 記錄編號"] = r.grnId ?? "";
  base["PO建立者(M18) / PO creator (M18)"] = r.poM18CreatorDisplay ?? "";
  return base;
}

const GRN_SHEET_DETAIL = "PO入倉記錄";
const GRN_SHEET_LISTED_PO = "已上架PO金額";

/** Rows for sheet "已上架PO金額" (ADMIN-only; do not add this sheet for other users). */
function buildListedPoAmountSheetRows(
  listed: ListedPoAmounts | undefined
): Record<string, string | number | undefined>[] {
  if (
    !listed ||
    (listed.currencyTotals.length === 0 &&
      listed.byPurchaseOrder.length === 0)
  ) {
    return [
      {
        "Note / 備註":
          "（篩選範圍內無已完成之 PO 行） / No completed PO lines in the selected range",
      },
    ];
  }
  const out: Record<string, string | number | undefined>[] = [];
  for (const c of listed.currencyTotals) {
    out.push({
      "Category / 類別": "貨幣小計 / Currency total",
      "Receipt Date / 收貨日期": c.receiptDate ?? "",
      "PO No. / 訂單編號": "",
      "Currency / 貨幣": c.currencyCode ?? "",
      "Total Amount / 金額": moneyCellValue(c.totalAmount),
      "GRN Code(s) / M18 入倉單號": "",
    });
  }
  for (const p of listed.byPurchaseOrder) {
    out.push({
      "Category / 類別": "訂單 / PO",
      "Receipt Date / 收貨日期": p.receiptDate ?? "",
      "PO No. / 訂單編號": p.poCode ?? "",
      "Currency / 貨幣": p.currencyCode ?? "",
      "Total Amount / 金額": moneyCellValue(p.totalAmount),
      "GRN Code(s) / M18 入倉單號": p.grnCodes ?? "",
    });
  }
  return out;
}

/**
 * Generate and download GRN report as Excel.
 * Sheet "已上架PO金額" is included only when `includeFinancialColumns` is true (ADMIN).
 */
export async function generateGrnReportExcel(
  criteria: Record<string, string>,
  reportTitle: string = "PO 入倉記錄",
  /** Only users with ADMIN authority should pass true (must match backend). */
  includeFinancialColumns: boolean = false
): Promise<void> {
  const { rows, listedPoAmounts } = await fetchGrnReportData(criteria);
  const excelRows = rows.map((r) => toExcelRow(r, includeFinancialColumns));
  const start = criteria.receiptDateStart;
  const end = criteria.receiptDateEnd;
  let datePart: string;
  if (start && end && start === end) {
    datePart = start;
  } else if (start || end) {
    datePart = `${start || ""}_to_${end || ""}`;
  } else {
    datePart = new Date().toISOString().slice(0, 10);
  }
  const safeDatePart = datePart.replace(/[^\d\-_/]/g, "");
  const filename = `${reportTitle}_${safeDatePart}`;

  if (includeFinancialColumns) {
    const sheet2 = buildListedPoAmountSheetRows(listedPoAmounts);
    exportMultiSheetToXlsx(
      [
        { name: GRN_SHEET_DETAIL, rows: excelRows as Record<string, unknown>[] },
        { name: GRN_SHEET_LISTED_PO, rows: sheet2 as Record<string, unknown>[] },
      ],
      filename
    );
  } else {
    exportChartToXlsx(excelRows as Record<string, unknown>[], filename, GRN_SHEET_DETAIL);
  }
}
