"use client";

import * as React from "react";

import { FileUpload } from "@/components/medora/file-upload";
import { kes } from "@/components/medora/payroll";
import { ean13Check } from "@/components/medora/print";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import { NativeSelect, NativeSelectOption } from "@/components/ui/native-select";
import { Textarea } from "@/components/ui/textarea";
import { cn } from "@/lib/utils";

/*
 * The full product record (IN-01) with its eTIMS codes (IN-04). Lists (categories, brands, units, eTIMS
 * codes, shelves, tax codes) come from the managed setup lists, never free text, so reports group cleanly
 * and KRA accepts the codes. A service drops the stock, buying and shelf fields.
 */

export type ProductDraft = {
  type: "Product" | "Service";
  name: string;
  code: string;
  barcode: string;
  description: string;
  category: string;
  subCategory: string;
  brand: string;
  unit: string;
  supplier: string;
  cost: string;
  price: string;
  taxCode: string;
  rx: boolean;
  /** Lowest margin the till sells at without approval, as a % of the selling price. Blank for none. */
  minMargin: string;
  /** Off for things sold without counting (carrier bags): no stock, batches or reorder alerts. */
  manageStock: boolean;
  /** Uploaded file or a link; shown on till tiles and the online shop. */
  image: string;
  reorderLevel: string;
  reorderQty: string;
  shelf: string;
  hsCode: string;
  itemClass: string;
  itemType: string;
  origin: string;
  packaging: string;
};

export type ProductLists = {
  categories: Record<string, string[]>;
  brands: string[];
  units: string[];
  suppliers: string[];
  taxCodes: { code: string; label: string }[];
  shelves: string[];
  itemClasses: { code: string; label: string }[];
  itemTypes: { code: string; label: string }[];
  origins: { code: string; label: string }[];
  packaging: { code: string; label: string }[];
};

type Problems = Partial<Record<keyof ProductDraft, string>>;
const isMoney = (s: string) => /^\d+(\.\d{1,2})?$/.test(s.replace(/,/g, ""));
const num = (s: string) => Number(s.replace(/,/g, ""));

/** Blocking problems, and eTIMS gaps reported separately: a product may be saved without them but can't go on an eTIMS receipt (IG-08). */
export function productProblems(d: ProductDraft, taken: { codes: string[]; barcodes: string[] }, lists: ProductLists): { problems: Problems; etimsGaps: string[] } {
  const p: Problems = {};
  const svc = d.type === "Service";
  if (!d.name.trim()) p.name = "Enter the name as it should print on receipts.";
  if (!d.code.trim()) p.code = "Every item needs a code.";
  else if (taken.codes.includes(d.code.trim().toUpperCase())) p.code = "Another item has this code.";
  if (!svc && d.barcode) {
    const b = d.barcode.replace(/\s/g, "");
    if (!/^\d{8}$|^\d{12,13}$/.test(b)) p.barcode = "Barcodes are 8, 12 or 13 digits.";
    else if (b.length === 13 && ean13Check(b.slice(0, 12)) !== Number(b[12])) p.barcode = `The last digit should be ${ean13Check(b.slice(0, 12))}: check it was scanned or typed correctly.`;
    else if (taken.barcodes.includes(b)) p.barcode = "Another product has this barcode. Scan it at the till to see which.";
  }
  if (!d.category) p.category = "Choose a category.";
  else if (d.subCategory && !(lists.categories[d.category] ?? []).includes(d.subCategory)) p.subCategory = `${d.subCategory} isn't under ${d.category}.`;
  if (!svc && !d.unit) p.unit = "Choose the unit stock is counted in.";
  if (!d.taxCode) p.taxCode = "Choose the tax code; the till and VAT report use it.";
  if (!isMoney(d.price) || num(d.price) <= 0) p.price = "Enter the selling price.";
  if (!svc) {
    if (!isMoney(d.cost)) p.cost = "Enter the purchase price.";
    else if (isMoney(d.price) && num(d.price) < num(d.cost)) p.price = `This sells below cost (${kes(num(d.cost))}). Correct the price; selling below cost needs approval at the till instead.`;
    else if (isMoney(d.price) && /^\d+(\.\d+)?$/.test(d.minMargin) && num(d.price) > 0) {
      const m = ((num(d.price) - num(d.cost)) / num(d.price)) * 100;
      if (m < Number(d.minMargin)) p.price = `This gives a ${m.toFixed(1)}% margin, below the ${d.minMargin}% minimum. Raise the price or lower the minimum.`;
    }
    if (d.minMargin && (!/^\d+(\.\d+)?$/.test(d.minMargin) || Number(d.minMargin) >= 100)) p.minMargin = "A percentage under 100.";
    if (d.reorderLevel && !/^\d+$/.test(d.reorderLevel)) p.reorderLevel = "A whole number.";
    if (d.reorderQty && !/^\d+$/.test(d.reorderQty)) p.reorderQty = "A whole number.";
    if (/^\d+$/.test(d.reorderQty) && Number(d.reorderQty) === 0) p.reorderQty = "Reorder at least 1, or leave it blank to use the suggestion.";
  }
  if (d.hsCode && !/^\d{4,10}$/.test(d.hsCode.replace(/[\s.]/g, ""))) p.hsCode = "HS codes are 4 to 10 digits, e.g. 3004.90.";
  const etimsGaps: string[] = [];
  if (!d.itemClass) etimsGaps.push("item class");
  if (!d.itemType) etimsGaps.push("item type");
  if (!d.origin) etimsGaps.push("country of origin");
  if (!svc && !d.packaging) etimsGaps.push("packaging unit");
  return { problems: p, etimsGaps };
}

const SECTIONS: { id: string; title: string; keys: (keyof ProductDraft)[]; product?: boolean }[] = [
  { id: "basics", title: "Basics", keys: ["name", "code", "barcode", "description"] },
  { id: "class", title: "Classification", keys: ["category", "subCategory", "brand", "unit"] },
  { id: "price", title: "Price and tax", keys: ["cost", "price", "minMargin", "taxCode", "supplier"] },
  { id: "stock", title: "Stock and shelf", keys: ["reorderLevel", "reorderQty", "shelf"], product: true },
  { id: "etims", title: "eTIMS", keys: ["itemClass", "itemType", "origin", "packaging", "hsCode"] },
];

/**
 * `onImageFile` (card 010): a live page receives the chosen image file (null when removed) and uploads
 * it once the product is saved. Without it (the demo), only the file name is kept, as before.
 */
export function ProductRecordForm({ d, onChange, lists, problems, etimsGaps, show, onImageFile }: { d: ProductDraft; onChange: (d: ProductDraft) => void; lists: ProductLists; problems: Problems; etimsGaps: string[]; show: boolean; onImageFile?: (file: File | null) => void }) {
  const [tab, setTab] = React.useState("basics");
  const svc = d.type === "Service";
  const P = show ? problems : {};
  const set = <K extends keyof ProductDraft>(k: K, v: ProductDraft[K]) => onChange({ ...d, [k]: v });
  const sections = SECTIONS.filter((s) => !(svc && s.product));
  const count = (keys: (keyof ProductDraft)[]) => keys.filter((k) => P[k]).length;
  const current = sections.find((s) => s.id === tab) ?? sections[0];
  const cost = num(d.cost);
  const price = num(d.price);
  const margin = isMoney(d.cost) && isMoney(d.price) && price > 0 ? ((price - cost) / price) * 100 : null;

  const field = (k: keyof ProductDraft, label: string, node: React.ReactNode, hint?: React.ReactNode, wide?: boolean) => (
    <div className={cn("space-y-1", wide && "sm:col-span-2")} data-invalid={!!P[k] || undefined}>
      <label htmlFor={`pr-${k}`} className="text-sm font-medium">
        {label}
      </label>
      {node}
      {P[k] ? <p className="text-xs text-status-error-text">{P[k]}</p> : hint ? <p className="text-xs text-muted-foreground">{hint}</p> : null}
    </div>
  );
  const input = (k: keyof ProductDraft, extra?: React.ComponentProps<typeof Input>) => <Input id={`pr-${k}`} value={String(d[k])} onChange={(e) => set(k, e.target.value as never)} aria-invalid={!!P[k]} {...extra} />;
  const select = (k: keyof ProductDraft, options: { value: string; label: string }[], empty = "Choose…") => (
    <NativeSelect id={`pr-${k}`} value={String(d[k])} onChange={(e) => set(k, e.target.value as never)} aria-invalid={!!P[k]}>
      <NativeSelectOption value="">{empty}</NativeSelectOption>
      {options.map((o) => (
        <NativeSelectOption key={o.value} value={o.value}>
          {o.label}
        </NativeSelectOption>
      ))}
    </NativeSelect>
  );
  const plain = (xs: string[]) => xs.map((x) => ({ value: x, label: x }));
  const coded = (xs: { code: string; label: string }[]) => xs.map((x) => ({ value: x.code, label: `${x.code} · ${x.label}` }));

  return (
    <div className="space-y-4">
      <div className="flex flex-wrap items-center gap-3">
        <div role="radiogroup" aria-label="Item type" className="inline-flex overflow-hidden rounded-md border border-[var(--color-border-panel)] text-sm bg-card">
          {(["Product", "Service"] as const).map((k) => (
            <button key={k} type="button" role="radio" aria-checked={d.type === k} onClick={() => set("type", k)} className={cn("cursor-pointer px-3 py-1.5", d.type === k ? "bg-[var(--color-bg-selected)] font-medium" : "text-muted-foreground hover:bg-muted")}>
              {k === "Product" ? "Product (has stock)" : "Service (no stock)"}
            </button>
          ))}
        </div>
        {etimsGaps.length ? (
          <span className="rounded bg-status-warning-bg px-2 py-0.5 text-xs font-medium text-status-warning-text">eTIMS: {etimsGaps.length} code{etimsGaps.length === 1 ? "" : "s"} missing</span>
        ) : (
          <span className="rounded bg-status-success-bg px-2 py-0.5 text-xs font-medium text-status-success-text">eTIMS codes complete</span>
        )}
      </div>

      <div role="tablist" aria-label="Product record" className="flex flex-wrap gap-1 border-b border-border">
        {sections.map((s) => {
          const c = count(s.keys);
          const warn = s.id === "etims" && etimsGaps.length > 0;
          return (
            <button key={s.id} type="button" role="tab" aria-selected={current.id === s.id} onClick={() => setTab(s.id)} className={cn("-mb-px flex cursor-pointer items-center gap-1.5 border-b-2 px-3 py-1.5 text-sm", current.id === s.id ? "border-primary font-medium" : "border-transparent text-muted-foreground hover:text-foreground")}>
              {s.title}
              {c ? <span className="rounded bg-status-error-bg px-1 text-[11px] text-status-error-text">{c}</span> : warn ? <span className="rounded bg-status-warning-bg px-1 text-[11px] text-status-warning-text">{etimsGaps.length}</span> : null}
            </button>
          );
        })}
      </div>

      <div className="grid gap-4 sm:grid-cols-2">
        {current.id === "basics" ? (
          <>
            {field("name", "Name", input("name"), "As printed on receipts and labels.", true)}
            {field("code", "Item code", input("code", { className: "font-mono uppercase", onChange: (e) => set("code", e.target.value.toUpperCase()) }), "Suggested from the category; change it if you use your own codes.")}
            {!svc ? field("barcode", "Barcode (optional)", input("barcode", { className: "font-mono", inputMode: "numeric" }), "Scan it into this box. A product has one barcode.") : null}
            {field("description", "Description (optional)", <Textarea id="pr-description" rows={2} value={d.description} onChange={(e) => set("description", e.target.value)} />, "Searchable at the till; not printed.", true)}
            <div className="sm:col-span-2">
              <FileUpload label="Product image (optional)" hint="JPG or PNG under 1 MB, or paste a link. Shown on till tiles and the online shop." kind="image" accept={[".jpg", ".jpeg", ".png"]} maxBytes={1024 * 1024} compact allowUrl upload={async (_f, prog) => prog(100)} onReady={(file) => {
                  set("image", file.name);
                  onImageFile?.(file);
                }} onRemove={() => {
                  set("image", "");
                  onImageFile?.(null);
                }} />
            </div>
          </>
        ) : current.id === "class" ? (
          <>
            {field("category", "Category", select("category", plain(Object.keys(lists.categories))))}
            {field("subCategory", "Sub-category (optional)", select("subCategory", plain(lists.categories[d.category] ?? []), d.category ? "None" : "Choose a category first"))}
            {field("brand", "Brand (optional)", select("brand", plain(lists.brands), "None"))}
            {!svc ? field("unit", "Unit", select("unit", plain(lists.units)), "What stock is counted in. Packs (strip, box) are set up after saving.") : null}
          </>
        ) : current.id === "price" ? (
          <>
            {!svc ? field("cost", "Purchase price", input("cost", { inputMode: "decimal", className: "tabular-nums" }), "Per unit, before VAT. Updated from goods received.") : null}
            {field("price", "Selling price", input("price", { inputMode: "decimal", className: "tabular-nums" }), margin != null ? `Margin ${margin.toFixed(1)}% on the selling price.` : undefined)}
            {field("taxCode", "Tax code", select("taxCode", lists.taxCodes.map((t) => ({ value: t.code, label: `${t.code} · ${t.label}` }))))}
            {!svc ? field("minMargin", "Minimum margin, % (optional)", input("minMargin", { inputMode: "decimal", className: "tabular-nums" }), "Selling below it at the till needs a manager's approval.") : null}
            {!svc ? field("supplier", "Usual supplier (optional)", select("supplier", plain(lists.suppliers), "None"), "Suggested first when ordering.") : null}
            <div className="flex items-start gap-2 sm:col-span-2">
              <Checkbox id="pr-rx" checked={d.rx} onCheckedChange={(v) => set("rx", !!v)} />
              <label htmlFor="pr-rx" className="text-sm">
                Prescription required
                <span className="block text-xs text-muted-foreground">The till asks for a prescription before selling it, and it counts as Rx in reports.</span>
              </label>
            </div>
          </>
        ) : current.id === "stock" ? (
          <>
            <div className="flex items-start gap-2 sm:col-span-2">
              <Checkbox id="pr-manageStock" checked={d.manageStock} onCheckedChange={(v) => set("manageStock", !!v)} />
              <label htmlFor="pr-manageStock" className="text-sm">
                Manage stock
                <span className="block text-xs text-muted-foreground">Off for things sold without counting, such as carrier bags: no stock levels, batches or reorder alerts.</span>
              </label>
            </div>
            {d.manageStock ? (
              <>
                {field("reorderLevel", "Reorder level", input("reorderLevel", { inputMode: "numeric", className: "tabular-nums" }), `Flagged as low below this many ${d.unit ? d.unit.toLowerCase() + "s" : "units"}, per branch.`)}
                {field("reorderQty", "Reorder quantity (optional)", input("reorderQty", { inputMode: "numeric", className: "tabular-nums" }), "Blank to use the suggestion from recent sales and lead time.")}
              </>
            ) : null}
            {field("shelf", "Shelf (optional)", select("shelf", plain(lists.shelves), "Not assigned"), "Shown at the till and on picking lists.")}
          </>
        ) : (
          <>
            <p className="text-sm text-muted-foreground sm:col-span-2">KRA&apos;s codes for this item. They&apos;re needed before it can be sold on an eTIMS receipt; the item is registered with KRA once they&apos;re complete.</p>
            {field("itemClass", "Item class", select("itemClass", coded(lists.itemClasses)))}
            {field("itemType", "Item type", select("itemType", coded(lists.itemTypes)))}
            {field("origin", "Country of origin", select("origin", coded(lists.origins)))}
            {!svc ? field("packaging", "Packaging unit", select("packaging", coded(lists.packaging))) : null}
            {field("hsCode", "HS code (optional)", input("hsCode", { className: "font-mono", inputMode: "numeric" }), "Customs tariff code, from the supplier's invoice for imports.")}
          </>
        )}
      </div>
    </div>
  );
}
