export interface SubmitNewProductsArgs {
  products: Array<Record<string, unknown>>;
  environment: "dev" | "prod";
  useTestDataSource: boolean;
  employeeId?: number;
}

export interface SubmitNewProductsResponse {
  success: boolean;
  message?: string;
  data?: unknown;
  error?: unknown;
}

export interface PoLineItemSubmit {
  pid: number;
  qty: number;
}

export interface SubmitNewPurchaseOrderArgs {
  supplierId: number | string;
  items: PoLineItemSubmit[];
}

export interface SubmitNewPurchaseOrderResponse {
  success: boolean;
  poId?: number;
  message?: string;
  error?: unknown;
  raw?: unknown;
}

export interface AddProductsToPurchaseOrderArgs {
  poId: number | string;
  items: PoLineItemSubmit[];
}

export interface AddProductsToPurchaseOrderResponse {
  success: boolean;
  message?: string;
  error?: unknown;
  raw?: unknown;
}

export interface CreateProductCategoryArgs {
  masterCatId: string | number;
  name: string;
  environment?: "dev" | "prod";
  image?: string;
  nameForCustoms?: string;
  taxCodeId?: string | number;
}

export interface CreateProductCategoryResponse {
  success: boolean;
  message?: string;
  data?: unknown;
  error?: unknown;
  category?: unknown;
}

// Relative URLs — same-origin to the browser. In production, Caddy on
// tools.acherryontop.com reverse-proxies /apiv2/* to backend.acherryontop.com
// (and /apiv2-test/* to work-test-backend.acherryontop.com via Vite in dev).
// The prod endpoints rely on a session cookie scoped to `.acherryontop.com`
// (sent via credentials: 'include' below); the dev/test endpoint instead
// receives an auth token in the request body (VITE_APIV2_AUTH_TOKEN).
const DEV_ENDPOINT = "/apiv2-test/product/setup_new";
const DEV_CREATE_CATEGORY_ENDPOINT = "/apiv2-test/prod_cat/new";
const PROD_ENDPOINT = "/apiv2/product/setup_new";
const PROD_CREATE_CATEGORY_ENDPOINT = "/apiv2/prod_cat/new";

const isHtmlResponse = (payload: string) => {
  const trimmed = payload.trim();
  return trimmed.startsWith("<!DOCTYPE html") || trimmed.startsWith("<html");
};

export async function submitNewProducts({
  products,
  environment,
  useTestDataSource,
}: SubmitNewProductsArgs): Promise<SubmitNewProductsResponse> {
  const baseUrl = environment === "dev" ? DEV_ENDPOINT : PROD_ENDPOINT;
  const targetUrl = useTestDataSource ? `${baseUrl}?use_test_data_source=1` : baseUrl;

  const payload = new URLSearchParams();
  const serializedProducts = JSON.stringify(products);
  payload.append("products", serializedProducts);

  let response: Response;

  const fetchOptions: RequestInit = {
    method: "POST",
    headers: {
      "Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
    },
    body: payload,
  };

  // Authentication strategy depends on endpoint
  if (environment === "dev") {
    // Test endpoint: Use auth token in request body
    const authToken = import.meta.env.VITE_APIV2_AUTH_TOKEN;
    if (authToken) {
      payload.append("auth", authToken);
      fetchOptions.body = payload;
    }
  } else {
    // Prod endpoint: Use cookies (proxied in both dev and production)
    fetchOptions.credentials = "include";
  }

  try {
    response = await fetch(targetUrl, fetchOptions);
  } catch (networkError) {
    throw new Error(networkError instanceof Error ? networkError.message : "Network request failed");
  }

  const rawBody = await response.text();

  if (isHtmlResponse(rawBody)) {
    throw new Error("Backend authentication required. Please ensure you are logged into the backend system.");
  }

  let parsed: unknown;
  try {
    parsed = JSON.parse(rawBody);
  } catch {
    const message = `Unexpected response from backend (${response.status}).`;
    throw new Error(message);
  }

  if (!parsed || typeof parsed !== "object") {
    throw new Error("Empty response from backend");
  }

  const parsedResponse = parsed as SubmitNewProductsResponse & Record<string, unknown>;
  const extraFields = parsedResponse as Record<string, unknown>;
  const normalizedResponse: SubmitNewProductsResponse = {
    success: Boolean(parsedResponse.success),
    message: typeof parsedResponse.message === "string" ? parsedResponse.message : undefined,
    data: parsedResponse.data,
    error: parsedResponse.error ?? extraFields.errors ?? extraFields.error_msg,
  };

  if (!response.ok || !normalizedResponse.success) {
    return normalizedResponse;
  }

  return normalizedResponse;
}

export async function createProductCategory({
  masterCatId,
  name,
  environment = "prod",
  image,
  nameForCustoms,
  taxCodeId,
}: CreateProductCategoryArgs): Promise<CreateProductCategoryResponse> {
  const targetUrl = environment === "dev" ? DEV_CREATE_CATEGORY_ENDPOINT : PROD_CREATE_CATEGORY_ENDPOINT;

  const payload = new URLSearchParams();
  payload.append("master_cat_id", masterCatId.toString());
  payload.append("name", name);

  if (nameForCustoms) {
    payload.append("name_for_customs", nameForCustoms);
  }

  if (image) {
    payload.append("image", image);
  }

  if (typeof taxCodeId !== "undefined" && taxCodeId !== null) {
    payload.append("tax_code_id", taxCodeId.toString());
  }

  let response: Response;

  const fetchOptions: RequestInit = {
    method: "POST",
    headers: {
      "Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
    },
    body: payload,
  };

  // Authentication strategy depends on endpoint
  if (environment === "dev") {
    // Test endpoint: Use auth token in request body
    const authToken = import.meta.env.VITE_APIV2_AUTH_TOKEN;
    if (authToken) {
      payload.append("auth", authToken);
      fetchOptions.body = payload;
    }
  } else {
    // Prod endpoint: Use cookies (proxied in both dev and production)
    fetchOptions.credentials = "include";
  }

  try {
    response = await fetch(targetUrl, fetchOptions);
  } catch (networkError) {
    throw new Error(networkError instanceof Error ? networkError.message : "Network request failed");
  }

  const rawBody = await response.text();

  if (isHtmlResponse(rawBody)) {
    throw new Error("Backend authentication required. Please ensure you are logged into the backend system.");
  }

  let parsed: unknown;
  try {
    parsed = JSON.parse(rawBody);
  } catch {
    const message = `Unexpected response from backend (${response.status}).`;
    throw new Error(message);
  }

  if (!parsed || typeof parsed !== "object") {
    throw new Error("Empty response from backend");
  }

  const parsedRecord = parsed as Record<string, unknown>;
  const normalizedResponse: CreateProductCategoryResponse = {
    success: Boolean(parsedRecord.success ?? parsedRecord.status ?? parsedRecord.result),
    message: typeof parsedRecord.message === "string" ? parsedRecord.message : undefined,
    data: parsedRecord.data ?? parsedRecord.category ?? parsedRecord.result,
    error: parsedRecord.error ?? parsedRecord.errors ?? parsedRecord.error_msg,
    category: parsedRecord.category,
  };

  if (!response.ok || !normalizedResponse.success) {
    return normalizedResponse;
  }

  return normalizedResponse;
}

/**
 * Creates a new purchase order on the legacy PHP backend.
 *
 * Mirrors the auth/serialization pattern of `submitNewProducts`:
 *  - URL-encoded body
 *  - cookie-based auth (`credentials: 'include'`)
 *  - HTML response → "Backend authentication required" guard
 *
 * The endpoint accepts a JSON array of `{pid, qty}` items in the `items` body
 * field, with the supplier ID as a path parameter. Returns `{po_id: number}`
 * on success. Designed to be called from anywhere in the app — not just the
 * Create PO page.
 */
export async function submitNewPurchaseOrder({
  supplierId,
  items,
}: SubmitNewPurchaseOrderArgs): Promise<SubmitNewPurchaseOrderResponse> {
  if (!supplierId) {
    throw new Error("supplierId is required");
  }
  if (!Array.isArray(items) || items.length === 0) {
    throw new Error("At least one item is required");
  }

  const cleanItems = items
    .map((i) => ({ pid: Number(i.pid), qty: Number(i.qty) }))
    .filter((i) => Number.isInteger(i.pid) && i.pid > 0 && Number.isFinite(i.qty) && i.qty > 0);

  if (cleanItems.length === 0) {
    throw new Error("No valid items to submit");
  }

  const targetUrl = `/apiv2/po/new/${encodeURIComponent(String(supplierId))}`;

  const payload = new URLSearchParams();
  payload.append("items", JSON.stringify(cleanItems));

  let response: Response;
  try {
    response = await fetch(targetUrl, {
      method: "POST",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
      },
      body: payload,
      credentials: "include",
    });
  } catch (networkError) {
    throw new Error(networkError instanceof Error ? networkError.message : "Network request failed");
  }

  const rawBody = await response.text();

  if (isHtmlResponse(rawBody)) {
    throw new Error("Backend authentication required. Please ensure you are logged into the backend system.");
  }

  let parsed: unknown;
  try {
    parsed = JSON.parse(rawBody);
  } catch {
    throw new Error(`Unexpected response from backend (${response.status}).`);
  }

  if (!parsed || typeof parsed !== "object") {
    throw new Error("Empty response from backend");
  }

  const record = parsed as Record<string, unknown>;
  // The PHP /apiv2 backend wraps successful responses in an envelope:
  //   {"success": true, "data": { "po_id": "32705" }}
  // po_id can appear either at the top level (legacy shape) OR nested
  // inside `data` (current shape), and the value is sometimes a string
  // (e.g. "32705") rather than a number. We look in both locations and
  // coerce to Number to handle both cases.
  const data =
    record.data && typeof record.data === "object"
      ? (record.data as Record<string, unknown>)
      : {};
  const rawPoId = record.po_id ?? record.poId ?? data.po_id ?? data.poId;
  const poIdNum = typeof rawPoId === "number" ? rawPoId : Number(rawPoId);
  const hasValidPoId = Number.isFinite(poIdNum) && poIdNum > 0;
  // Trust the backend's own `success` flag when it's present — it's the
  // authoritative signal. Fall back to "HTTP OK + valid po_id" for older
  // response shapes that don't include the flag.
  const backendSuccess =
    record.success === true ||
    record.success === "true" ||
    record.success === 1;
  const success = response.ok && hasValidPoId && (backendSuccess || record.success === undefined);

  return {
    success,
    poId: success ? poIdNum : undefined,
    message: typeof record.message === "string" ? record.message : undefined,
    error: record.error ?? record.errors ?? record.error_msg,
    raw: parsed,
  };
}

/**
 * Adds line items to an existing purchase order on the legacy PHP backend.
 *
 * Mirrors `submitNewPurchaseOrder` exactly except the URL takes a po_id path
 * param and we don't expect (or use) a po_id in the response. Same
 * URL-encoded body shape, same cookie-auth flow, same HTML-response guard.
 */
export async function addProductsToPurchaseOrder({
  poId,
  items,
}: AddProductsToPurchaseOrderArgs): Promise<AddProductsToPurchaseOrderResponse> {
  const poIdNum = Number(poId);
  if (!Number.isInteger(poIdNum) || poIdNum <= 0) {
    throw new Error("A valid PO number is required");
  }
  if (!Array.isArray(items) || items.length === 0) {
    throw new Error("At least one item is required");
  }

  const cleanItems = items
    .map((i) => ({ pid: Number(i.pid), qty: Number(i.qty) }))
    .filter((i) => Number.isInteger(i.pid) && i.pid > 0 && Number.isFinite(i.qty) && i.qty > 0);

  if (cleanItems.length === 0) {
    throw new Error("No valid items to submit");
  }

  const targetUrl = `/apiv2/po/add_products/${encodeURIComponent(String(poIdNum))}`;

  const payload = new URLSearchParams();
  payload.append("items", JSON.stringify(cleanItems));

  let response: Response;
  try {
    response = await fetch(targetUrl, {
      method: "POST",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
      },
      body: payload,
      credentials: "include",
    });
  } catch (networkError) {
    throw new Error(networkError instanceof Error ? networkError.message : "Network request failed");
  }

  const rawBody = await response.text();

  if (isHtmlResponse(rawBody)) {
    throw new Error("Backend authentication required. Please ensure you are logged into the backend system.");
  }

  let parsed: unknown;
  try {
    parsed = JSON.parse(rawBody);
  } catch {
    throw new Error(`Unexpected response from backend (${response.status}).`);
  }

  if (!parsed || typeof parsed !== "object") {
    throw new Error("Empty response from backend");
  }

  const record = parsed as Record<string, unknown>;
  const backendSuccess =
    record.success === true ||
    record.success === "true" ||
    record.success === 1;
  const success = response.ok && (backendSuccess || record.success === undefined);

  return {
    success,
    message: typeof record.message === "string" ? record.message : undefined,
    error: record.error ?? record.errors ?? record.error_msg,
    raw: parsed,
  };
}
