const BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL ?? "/api";

function getAuthHeaders(): Record<string, string> {
  const token = typeof window !== "undefined" ? localStorage.getItem("ssmt_token") : null;
  return token ? { Authorization: `Bearer ${token}` } : {};
}

async function apiFetch(path: string, init?: RequestInit): Promise<string> {
  const url = `${BASE_URL}${path}`;
  const response = await fetch(url, {
    ...init,
    headers: { ...getAuthHeaders(), ...(init?.headers ?? {}) },
  });

  if (!response.ok) {
    const body = await response.text();
    throw new Error(`API request failed with status ${response.status}: ${body}`);
  }

  return response.text();
}

export { apiFetch };

// ── Interfaces ───────────────────────────────────────────────────────────────

export interface InventorySummary {
  totalAvailableMt: number;
  totalEmptyMt: number;
  thresholdTargetMt: number;
  hasReachedThreshold: boolean;
  invoiceRequiredForStockIn: boolean;
  expiringWithinSixMonths: number;
  pendingReviews: number;
}

export interface InventoryRow {
  id: string;
  warehouse: string | null;
  itemCode: string | null;
  itemName: string | null;
  batchNumber: string | null;
  expiryDate: string | null;
  inboundMt: number;
  outboundMt: number;
  availableMt: number;
  thresholdTargetMt: number;
  thresholdProgressPct: number;
}

export interface ExpiryRow {
  warehouse: string | null;
  itemCode: string | null;
  itemName: string | null;
  batchNumber: string | null;
  expiryDate: string | null;
  availableMt: number;
}

export interface WarehouseRecord {
  _id: string;
  name: string;
  code: string;
  aliases: string[];
  active: boolean;
}

export interface ItemRecord {
  _id: string;
  itemCode: string;
  itemName: string | null;
  description: string | null;
  brand: string | null;
  barcode: string | null;
  countryOfOrigin: string | null;
  blend: string | null;
  grainType: string | null;
  varietyType: string | null;
  processType: string | null;
  unit: string | null;
  bagWeightKg: number | null;
  packing: string | null;
  variant: string | null;
  riceName: string | null;
  category: string | null;
  status: string | null;
}

export interface BatchRecord {
  id: string;
  batchNumber: string;
  expiryDate: string;
  availableBags?: number;
  availableMt: number;
}

export interface StockTransaction {
  id: string;
  type: "inbound" | "outbound";
  warehouseId: string;
  itemId: string;
  batchId: string;
  quantityMt: number;
  transactionDate: string;
  approvalStatus: "pending_approval" | "approved" | "rejected";
  approvedBy: string | null;
  approvedAt: string | null;
  rejectedBy: string | null;
  rejectedAt: string | null;
  rejectedReason: string | null;
  submittedBy: string | null;
  warehouseName?: string | null;
  itemCode?: string | null;
  itemName?: string | null;
  batchNumber?: string | null;
  expiryDate?: string | null;
  jobCardReference?: string | null; // Optional job card reference
  createdAt: string;
}

export interface StockMovementSheet {
  id: string;
  companyName: string | null;
  reportTitle: string | null;
  stockReportFor: string | null;
  documentDate: string | null;
  documentNumber: string | null;
  referenceNumber: string | null;
  preparedBy: string | null;
  reviewedBy: string | null;
  approvedByField: string | null;
  totalBagsAll: number;
  totalMtAll: number;
  approvalStatus: "pending_approval" | "approved" | "rejected";
  approvedBy: string | null;
  approvedAt: string | null;
  rejectedBy: string | null;
  rejectedAt: string | null;
  rejectedReason: string | null;
  submittedBy: string | null;
  createdAt: string;
  lineItems?: StockSheetLineItem[];
}

export interface StockSheetLineItem {
  lineNumber: number;
  itemId: string;
  itemCode: string | null;
  barcode: string | null;
  itemName: string | null;
  blend: string | null;
  grainType: string | null;
  varietyType: string | null;
  processType: string | null;
  coo: string | null;
  unit: string | null;
  batchNumber: string;
  productionDate: string | null;
  expiryDate: string;
  warehouseBags: Record<string, number>;
  warehouseBagsNamed?: Record<string, number>;
  totalBags: number;
  totalMt: number;
  shipmentNo: string | null;
  qualityReportNo: string | null;
}

export interface ReportRow {
  id: string;
  date: string;
  type: "inbound" | "outbound";
  warehouse: string | null;
  itemCode: string | null;
  itemName: string | null;
  batchNumber: string | null;
  quantityMt: number;
  approvalStatus: string;
}

export interface WarehouseSummary {
  warehouse: string;
  totalInbound: number;
  totalOutbound: number;
  net: number;
}

export type UserRole = "store_keeper" | "store_manager" | "super_admin";

export interface UserRecord {
  id: string;
  email: string;
  name: string;
  role: UserRole;
  active: boolean;
  createdAt: string;
}

// ── Invoice Extraction ────────────────────────────────────────────────────────

export interface InvoiceExtractedFields {
  document_type: string | null;
  document_number: string | null;
  warehouse_name: string | null;
  item_code: string | null;
  item_name: string | null;
  batch_number: string | null;
  expiry_date: string | null;
  quantity_mt: number | null;
  document_date: string | null;
  reference_number: string | null;
  supplier_name: string | null;
  supplier_trn: string | null;
  buyer_name: string | null;
  buyer_trn: string | null;
  due_date: string | null;
  currency: string | null;
  payment_terms: string | null;
  total_amount: number | null;
  vat_amount: number | null;
  net_amount: number | null;
  unit: string | null;
  unit_price: number | null;
  all_batches: string | null;
  all_items: string | null;
}

export interface InvoiceExtraction {
  success: boolean;
  document_type: string;
  extracted_fields: InvoiceExtractedFields;
  validation_flags: string[];
  confidence: number;
}

export async function extractInvoice(file: File): Promise<InvoiceExtraction> {
  const formData = new FormData();
  formData.append("file", file);
  const url = `${BASE_URL}/extract/invoice`;
  const token = typeof window !== "undefined" ? localStorage.getItem("ssmt_token") : null;
  const res = await fetch(url, {
    method: "POST",
    headers: token ? { Authorization: `Bearer ${token}` } : {},
    body: formData,
  });
  if (!res.ok) {
    const body = await res.text();
    throw new Error(`Extraction failed (${res.status}): ${body}`);
  }
  return res.json() as Promise<InvoiceExtraction>;
}

export async function getInventorySummary(): Promise<InventorySummary> {
  return JSON.parse(await apiFetch("/inventory/summary")) as InventorySummary;
}

export async function getInventory(): Promise<InventoryRow[]> {
  return JSON.parse(await apiFetch("/inventory")) as InventoryRow[];
}

export async function getInventoryExpiry(months?: number, warehouses?: string[]): Promise<ExpiryRow[]> {
  const params = new URLSearchParams();
  if (months !== undefined) params.set("months", String(months));
  if (warehouses?.length) params.set("warehouses", warehouses.join(","));
  const path = `/inventory/expiry${params.toString() ? `?${params}` : ""}`;
  return JSON.parse(await apiFetch(path)) as ExpiryRow[];
}

export async function getExpiryDocumentsByWarehouseAndItem(
  warehouseIds: string[],
  itemCode: string
): Promise<ExpiryRow[]> {
  const params = new URLSearchParams();
  params.set("warehouses", warehouseIds.join(","));
  params.set("itemCode", itemCode);
  params.set("months", "24"); // Show all expiry within 24 months
  const path = `/inventory/expiry${params.toString() ? `?${params}` : ""}`;
  return JSON.parse(await apiFetch(path)) as ExpiryRow[];
}

// ── Warehouses ───────────────────────────────────────────────────────────────

export async function getWarehouses(): Promise<WarehouseRecord[]> {
  return JSON.parse(await apiFetch("/warehouses")) as WarehouseRecord[];
}

export async function createWarehouse(body: { name: string; code: string; aliases?: string[] }): Promise<WarehouseRecord> {
  return JSON.parse(
    await apiFetch("/warehouses", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(body),
    }),
  ) as WarehouseRecord;
}

export async function updateWarehouse(
  id: string,
  body: Partial<{ name: string; code: string; aliases: string[]; active: boolean }>,
): Promise<WarehouseRecord> {
  return JSON.parse(
    await apiFetch(`/warehouses/${id}`, {
      method: "PATCH",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(body),
    }),
  ) as WarehouseRecord;
}

// ── Access Control ──────────────────────────────────────────────────────────

export async function getUsers(): Promise<UserRecord[]> {
  return JSON.parse(await apiFetch("/auth/users")) as UserRecord[];
}

export async function createUser(body: {
  email: string;
  name: string;
  role: UserRole;
  password: string;
  active?: boolean;
}): Promise<UserRecord> {
  return JSON.parse(
    await apiFetch("/auth/users", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(body),
    }),
  ) as UserRecord;
}

export async function updateUser(
  id: string,
  body: Partial<{ email: string; name: string; role: UserRole; password: string; active: boolean }>,
): Promise<UserRecord> {
  return JSON.parse(
    await apiFetch(`/auth/users/${id}`, {
      method: "PATCH",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(body),
    }),
  ) as UserRecord;
}

export async function deleteUser(id: string): Promise<UserRecord> {
  return JSON.parse(await apiFetch(`/auth/users/${id}`, { method: "DELETE" })) as UserRecord;
}

// ── Items ────────────────────────────────────────────────────────────────────

export async function getItems(): Promise<ItemRecord[]> {
  return JSON.parse(await apiFetch("/items")) as ItemRecord[];
}

export async function getItemByCode(itemCode: string): Promise<ItemRecord> {
  return JSON.parse(await apiFetch(`/items/by-code/${encodeURIComponent(itemCode)}`)) as ItemRecord;
}

export async function searchItems(query: string): Promise<ItemRecord[]> {
  if (!query || query.trim().length < 2) {
    return [];
  }
  return JSON.parse(await apiFetch(`/items/search?q=${encodeURIComponent(query)}`)) as ItemRecord[];
}

export async function createItem(body: {
  itemCode: string;
  itemName: string;
  brand: string;
  barcode?: string;
  countryOfOrigin?: string;
  blend?: string;
  grainType?: string;
  varietyType?: string;
  processType?: string;
  unit?: string;
}): Promise<ItemRecord> {
  return JSON.parse(
    await apiFetch("/items", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(body),
    }),
  ) as ItemRecord;
}

export async function getBatches(itemId: string, warehouseId: string): Promise<BatchRecord[]> {
  return JSON.parse(await apiFetch(`/items/${itemId}/batches?warehouseId=${warehouseId}`)) as BatchRecord[];
}

export async function updateItem(
  id: string,
  body: { bagWeightKg?: number | null; unit?: string | null },
): Promise<ItemRecord> {
  return JSON.parse(
    await apiFetch(`/items/${id}`, {
      method: "PATCH",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(body),
    }),
  ) as ItemRecord;
}

// ── Stock In / Out ───────────────────────────────────────────────────────────

export async function createStockIn(body: {
  warehouseId: string;
  itemId: string;
  batchNumber: string;
  expiryDate: string;
  quantityMt: number;
  supplierName?: string;
  supplierTrn?: string;
  documentNumber?: string;
  documentDate?: string;
  referenceNumber?: string;
  unit?: string;
  unitPrice?: number;
}): Promise<StockTransaction> {
  return JSON.parse(
    await apiFetch("/stock-in", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(body),
    }),
  ) as StockTransaction;
}

export async function createStockOut(body: {
  warehouseId: string;
  itemId: string;
  batchId?: string; // Optional
  expiryDate?: string;
  quantityMt: number;
}): Promise<StockTransaction> {
  return JSON.parse(
    await apiFetch("/stock-out", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(body),
    }),
  ) as StockTransaction;
}

// ── Approvals ────────────────────────────────────────────────────────────────

export async function getPendingTransactions(): Promise<StockTransaction[]> {
  return JSON.parse(await apiFetch("/stock-transactions/pending")) as StockTransaction[];
}

export async function getAllTransactions(params?: {
  status?: string;
  page?: number;
  limit?: number;
}): Promise<StockTransaction[]> {
  const query = new URLSearchParams();
  if (params?.status && params.status !== "all") {
    query.set("status", params.status);
  }
  if (params?.page) {
    query.set("page", String(params.page));
  }
  if (params?.limit) {
    query.set("limit", String(params.limit));
  }
  const path = `/stock-transactions${query.toString() ? `?${query}` : ""}`;
  return JSON.parse(await apiFetch(path)) as StockTransaction[];
}

export async function approveTransaction(id: string): Promise<StockTransaction> {
  return JSON.parse(
    await apiFetch(`/stock-transactions/${id}/approve`, { method: "POST" }),
  ) as StockTransaction;
}

export async function rejectTransaction(id: string, reason: string): Promise<StockTransaction> {
  return JSON.parse(
    await apiFetch(`/stock-transactions/${id}/reject`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ reason }),
    }),
  ) as StockTransaction;
}

// ── Stock Movement Sheets ────────────────────────────────────────────────────

export async function getStockMovementSheets(): Promise<StockMovementSheet[]> {
  return JSON.parse(await apiFetch("/stock-movement-sheets")) as StockMovementSheet[];
}

export async function getStockMovementSheet(id: string): Promise<StockMovementSheet> {
  return JSON.parse(await apiFetch(`/stock-movement-sheets/${id}`)) as StockMovementSheet;
}

export async function createStockMovementSheet(body: {
  companyName?: string;
  reportTitle?: string;
  stockReportFor?: string;
  documentDate?: string;
  documentNumber?: string;
  referenceNumber?: string;
  preparedBy?: string;
  reviewedBy?: string;
  approvedByField?: string;
  invoice?: {
    documentNumber?: string | null;
    documentDate?: string | null;
    referenceNumber?: string | null;
    warehouseName?: string | null;
    itemCode?: string | null;
    itemName?: string | null;
    batchNumber?: string | null;
    allBatches?: string | null;
    expiryDate?: string | null;
    quantityMt?: number | null;
    unit?: string | null;
    unitPrice?: number | null;
    supplierName?: string | null;
    supplierTrn?: string | null;
    buyerName?: string | null;
    buyerTrn?: string | null;
    totalAmount?: number | null;
    vatAmount?: number | null;
    netAmount?: number | null;
    currency?: string | null;
    paymentTerms?: string | null;
    dueDate?: string | null;
  };
  lineItems: Array<{
    itemId: string;
    batchNumber: string;
    productionDate?: string;
    expiryDate: string;
    warehouseBags: Record<string, number>;
    totalMtOverride?: number | null;
    shipmentNo?: string;
    qualityReportNo?: string;
  }>;
}): Promise<StockMovementSheet> {
  return JSON.parse(
    await apiFetch("/stock-movement-sheets", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(body),
    }),
  ) as StockMovementSheet;
}

export async function approveStockMovementSheet(id: string): Promise<StockMovementSheet> {
  return JSON.parse(
    await apiFetch(`/stock-movement-sheets/${id}/approve`, { method: "POST" }),
  ) as StockMovementSheet;
}

export async function rejectStockMovementSheet(id: string, reason: string): Promise<StockMovementSheet> {
  return JSON.parse(
    await apiFetch(`/stock-movement-sheets/${id}/reject`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ reason }),
    }),
  ) as StockMovementSheet;
}

// ── Reports ──────────────────────────────────────────────────────────────────

export async function getTransactionReport(params: {
  warehouses?: string[];
  type?: "inbound" | "outbound" | "all";
  fromDate?: string;
  toDate?: string;
}): Promise<ReportRow[]> {
  const q = new URLSearchParams();
  if (params.warehouses?.length) q.set("warehouses", params.warehouses.join(","));
  if (params.type) q.set("type", params.type);
  if (params.fromDate) q.set("fromDate", params.fromDate);
  if (params.toDate) q.set("toDate", params.toDate);
  return JSON.parse(await apiFetch(`/reports/transactions${q.toString() ? `?${q}` : ""}`)) as ReportRow[];
}

export async function getReportSummary(params: {
  warehouses?: string[];
  type?: "inbound" | "outbound" | "all";
  fromDate?: string;
  toDate?: string;
}): Promise<WarehouseSummary[]> {
  const q = new URLSearchParams();
  if (params.warehouses?.length) q.set("warehouses", params.warehouses.join(","));
  if (params.type) q.set("type", params.type);
  if (params.fromDate) q.set("fromDate", params.fromDate);
  if (params.toDate) q.set("toDate", params.toDate);
  return JSON.parse(await apiFetch(`/reports/summary${q.toString() ? `?${q}` : ""}`)) as WarehouseSummary[];
}

export async function exportReportPdf(body: {
  warehouses?: string[];
  type?: string;
  fromDate?: string;
  toDate?: string;
  title?: string;
}): Promise<{ blob: Blob; fileName: string }> {
  const url = `${BASE_URL}/reports/export-pdf`;
  const response = await fetch(url, {
    method: "POST",
    headers: { "Content-Type": "application/json", ...getAuthHeaders() },
    body: JSON.stringify(body),
  });
  if (!response.ok) throw new Error(`Export failed (${response.status}): ${await response.text()}`);
  const disposition = response.headers.get("Content-Disposition") ?? "";
  const match = disposition.match(/filename="([^"]+)"/);
  const fileName = match?.[1] ?? `report-${Date.now()}.pdf`;
  return { blob: await response.blob(), fileName };
}

export async function generateExpiryReportPdf(body: {
  warehouses?: string[];
  items?: string[];
  months?: number;
  downloadedBy: string;
  reviewedBy?: string;
  approvedBy?: string;
}): Promise<{ blob: Blob; fileName: string }> {
  const url = `${BASE_URL}/inventory/expiry/report`;
  const response = await fetch(url, {
    method: "POST",
    headers: { "Content-Type": "application/json", ...getAuthHeaders() },
    body: JSON.stringify(body),
  });
  if (!response.ok) throw new Error(`Report failed (${response.status}): ${await response.text()}`);
  const disposition = response.headers.get("Content-Disposition") ?? "";
  const match = disposition.match(/filename="([^"]+)"/);
  const fileName = match?.[1] ?? `expiry-report-${Date.now()}.pdf`;
  return { blob: await response.blob(), fileName };
}
