import type { InventoryBomLineInput, InventoryItemInput, InventoryItemOptionDto } from "@mrp/shared/dist/inventory/types.js";
import { useEffect, useState } from "react";
import { Link, useNavigate, useParams } from "react-router-dom";

import { useAuth } from "../../auth/AuthProvider";
import { api, ApiError } from "../../lib/api";
import { emptyInventoryBomLineInput, emptyInventoryItemInput, inventoryStatusOptions, inventoryTypeOptions, inventoryUnitOptions } from "./config";

interface InventoryFormPageProps {
  mode: "create" | "edit";
}

export function InventoryFormPage({ mode }: InventoryFormPageProps) {
  const navigate = useNavigate();
  const { token } = useAuth();
  const { itemId } = useParams();
  const [form, setForm] = useState<InventoryItemInput>(emptyInventoryItemInput);
  const [componentOptions, setComponentOptions] = useState<InventoryItemOptionDto[]>([]);
  const [componentSearchTerms, setComponentSearchTerms] = useState<string[]>([]);
  const [activeComponentPicker, setActiveComponentPicker] = useState<number | null>(null);
  const [status, setStatus] = useState(mode === "create" ? "Create a new inventory item." : "Loading inventory item...");
  const [isSaving, setIsSaving] = useState(false);

  function getComponentOption(componentItemId: string) {
    return componentOptions.find((option) => option.id === componentItemId) ?? null;
  }

  function getComponentSku(componentItemId: string) {
    return getComponentOption(componentItemId)?.sku ?? "";
  }

  useEffect(() => {
    if (!token) {
      return;
    }

    api
      .getInventoryItemOptions(token)
      .then((options) => {
        const nextOptions = options.filter((option) => option.id !== itemId);
        setComponentOptions(nextOptions);
        setComponentSearchTerms((current) =>
          form.bomLines.map((line, index) => {
            if (current[index]?.trim()) {
              return current[index];
            }

            const match = nextOptions.find((option) => option.id === line.componentItemId);
            return match ? match.sku : "";
          })
        );
      })
      .catch(() => setComponentOptions([]));
  }, [form.bomLines, itemId, token]);

  useEffect(() => {
    if (mode !== "edit" || !token || !itemId) {
      return;
    }

    api
      .getInventoryItem(token, itemId)
      .then((item) => {
        setForm({
          sku: item.sku,
          name: item.name,
          description: item.description,
          type: item.type,
          status: item.status,
          unitOfMeasure: item.unitOfMeasure,
          isSellable: item.isSellable,
          isPurchasable: item.isPurchasable,
          defaultCost: item.defaultCost,
          notes: item.notes,
          bomLines: item.bomLines.map((line) => ({
            componentItemId: line.componentItemId,
            quantity: line.quantity,
            unitOfMeasure: line.unitOfMeasure,
            notes: line.notes,
            position: line.position,
          })),
        });
        setComponentSearchTerms(item.bomLines.map((line) => line.componentSku));
        setStatus("Inventory item loaded.");
      })
      .catch((error: unknown) => {
        const message = error instanceof ApiError ? error.message : "Unable to load inventory item.";
        setStatus(message);
      });
  }, [itemId, mode, token]);

  function updateField<Key extends keyof InventoryItemInput>(key: Key, value: InventoryItemInput[Key]) {
    setForm((current) => ({ ...current, [key]: value }));
  }

  function updateBomLine(index: number, nextLine: InventoryBomLineInput) {
    setForm((current) => ({
      ...current,
      bomLines: current.bomLines.map((line, lineIndex) => (lineIndex === index ? nextLine : line)),
    }));
  }

  function updateComponentSearchTerm(index: number, value: string) {
    setComponentSearchTerms((current) => {
      const nextTerms = [...current];
      nextTerms[index] = value;
      return nextTerms;
    });
  }

  function addBomLine() {
    setForm((current) => ({
      ...current,
      bomLines: [
        ...current.bomLines,
        {
          ...emptyInventoryBomLineInput,
          position: current.bomLines.length === 0 ? 10 : Math.max(...current.bomLines.map((line) => line.position)) + 10,
        },
      ],
    }));
    setComponentSearchTerms((current) => [...current, ""]);
  }

  function removeBomLine(index: number) {
    setForm((current) => ({
      ...current,
      bomLines: current.bomLines.filter((_line, lineIndex) => lineIndex !== index),
    }));
    setComponentSearchTerms((current) => current.filter((_term, termIndex) => termIndex !== index));
    setActiveComponentPicker((current) => (current === index ? null : current != null && current > index ? current - 1 : current));
  }

  async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!token) {
      return;
    }

    setIsSaving(true);
    setStatus("Saving inventory item...");

    try {
      const saved =
        mode === "create" ? await api.createInventoryItem(token, form) : await api.updateInventoryItem(token, itemId ?? "", form);
      navigate(`/inventory/items/${saved.id}`);
    } catch (error: unknown) {
      const message = error instanceof ApiError ? error.message : "Unable to save inventory item.";
      setStatus(message);
      setIsSaving(false);
    }
  }

  return (
    <form className="space-y-6" onSubmit={handleSubmit}>
      <section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
        <div className="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
          <div>
            <p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Inventory Editor</p>
            <h3 className="mt-2 text-xl font-bold text-text">{mode === "create" ? "New Item" : "Edit Item"}</h3>
            <p className="mt-2 max-w-2xl text-sm text-muted">
              Define item master data and the first revision of the bill of materials for assemblies and manufactured items.
            </p>
          </div>
          <Link
            to={mode === "create" ? "/inventory/items" : `/inventory/items/${itemId}`}
            className="inline-flex items-center justify-center rounded-2xl border border-line/70 px-2 py-2 text-sm font-semibold text-text"
          >
            Cancel
          </Link>
        </div>
      </section>
      <section className="space-y-4 rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
        <div className="grid gap-3 xl:grid-cols-2 2xl:grid-cols-4">
          <label className="block">
            <span className="mb-2 block text-sm font-semibold text-text">SKU</span>
            <input
              value={form.sku}
              onChange={(event) => updateField("sku", event.target.value)}
              className="w-full rounded-2xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand"
            />
          </label>
          <label className="block 2xl:col-span-2">
            <span className="mb-2 block text-sm font-semibold text-text">Item name</span>
            <input
              value={form.name}
              onChange={(event) => updateField("name", event.target.value)}
              className="w-full rounded-2xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand"
            />
          </label>
          <label className="block">
            <span className="mb-2 block text-sm font-semibold text-text">Default cost</span>
            <input
              type="number"
              min={0}
              step={0.01}
              value={form.defaultCost ?? ""}
              onChange={(event) => updateField("defaultCost", event.target.value === "" ? null : Number(event.target.value))}
              className="w-full rounded-2xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand"
            />
          </label>
        </div>
        <div className="grid gap-3 xl:grid-cols-4">
          <label className="block">
            <span className="mb-2 block text-sm font-semibold text-text">Type</span>
            <select
              value={form.type}
              onChange={(event) => updateField("type", event.target.value as InventoryItemInput["type"])}
              className="w-full rounded-2xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand"
            >
              {inventoryTypeOptions.map((option) => (
                <option key={option.value} value={option.value}>
                  {option.label}
                </option>
              ))}
            </select>
          </label>
          <label className="block">
            <span className="mb-2 block text-sm font-semibold text-text">Status</span>
            <select
              value={form.status}
              onChange={(event) => updateField("status", event.target.value as InventoryItemInput["status"])}
              className="w-full rounded-2xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand"
            >
              {inventoryStatusOptions.map((option) => (
                <option key={option.value} value={option.value}>
                  {option.label}
                </option>
              ))}
            </select>
          </label>
          <label className="block">
            <span className="mb-2 block text-sm font-semibold text-text">Unit of measure</span>
            <select
              value={form.unitOfMeasure}
              onChange={(event) => updateField("unitOfMeasure", event.target.value as InventoryItemInput["unitOfMeasure"])}
              className="w-full rounded-2xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand"
            >
              {inventoryUnitOptions.map((option) => (
                <option key={option.value} value={option.value}>
                  {option.label}
                </option>
              ))}
            </select>
          </label>
          <div className="grid gap-3 sm:grid-cols-2">
            <label className="flex items-center gap-3 rounded-2xl border border-line/70 bg-page px-2 py-2">
              <input type="checkbox" checked={form.isSellable} onChange={(event) => updateField("isSellable", event.target.checked)} />
              <span className="text-sm font-semibold text-text">Sellable</span>
            </label>
            <label className="flex items-center gap-3 rounded-2xl border border-line/70 bg-page px-2 py-2">
              <input
                type="checkbox"
                checked={form.isPurchasable}
                onChange={(event) => updateField("isPurchasable", event.target.checked)}
              />
              <span className="text-sm font-semibold text-text">Purchasable</span>
            </label>
          </div>
        </div>
        <label className="block">
          <span className="mb-2 block text-sm font-semibold text-text">Description</span>
          <textarea
            value={form.description}
            onChange={(event) => updateField("description", event.target.value)}
            rows={4}
            className="w-full rounded-3xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand"
          />
        </label>
        <label className="block">
          <span className="mb-2 block text-sm font-semibold text-text">Internal notes</span>
          <textarea
            value={form.notes}
            onChange={(event) => updateField("notes", event.target.value)}
            rows={4}
            className="w-full rounded-3xl border border-line/70 bg-page px-2 py-2 text-text outline-none transition focus:border-brand"
          />
        </label>
      </section>
      <section className="rounded-[28px] border border-line/70 bg-surface/90 p-4 shadow-panel 2xl:p-5">
        <div className="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
          <div>
            <p className="text-xs font-semibold uppercase tracking-[0.24em] text-muted">Bill Of Materials</p>
            <h4 className="mt-2 text-lg font-bold text-text">Component lines</h4>
            <p className="mt-2 text-sm text-muted">Add BOM components for manufactured or assembly items. Purchased and service items can be saved without BOM lines.</p>
          </div>
          <button
            type="button"
            onClick={addBomLine}
            className="inline-flex items-center justify-center rounded-2xl border border-line/70 px-2 py-2 text-sm font-semibold text-text"
          >
            Add BOM line
          </button>
        </div>
        {form.bomLines.length === 0 ? (
          <div className="mt-5 rounded-3xl border border-dashed border-line/70 bg-page/60 px-4 py-8 text-center text-sm text-muted">
            No BOM lines added yet.
          </div>
        ) : (
          <div className="mt-5 space-y-4">
            {form.bomLines.map((line, index) => (
              <div key={`${line.componentItemId}-${line.position}-${index}`} className="rounded-3xl border border-line/70 bg-page/60 p-3">
                <div className="grid gap-3 xl:grid-cols-[1.4fr_0.7fr_0.7fr_0.7fr_auto]">
                  <label className="block">
                    <span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">Component</span>
                    <div className="relative">
                      <input
                        value={componentSearchTerms[index] ?? getComponentSku(line.componentItemId)}
                        onChange={(event) => {
                          updateComponentSearchTerm(index, event.target.value);
                          updateBomLine(index, { ...line, componentItemId: "" });
                          setActiveComponentPicker(index);
                        }}
                        onFocus={() => setActiveComponentPicker(index)}
                        onBlur={() => {
                          window.setTimeout(() => {
                            setActiveComponentPicker((current) => (current === index ? null : current));
                            if (!form.bomLines[index]?.componentItemId) {
                              updateComponentSearchTerm(index, "");
                            } else {
                              updateComponentSearchTerm(index, getComponentSku(form.bomLines[index].componentItemId));
                            }
                          }, 120);
                        }}
                        placeholder="Search by SKU"
                        className="w-full rounded-2xl border border-line/70 bg-surface px-2 py-2 text-text outline-none transition focus:border-brand"
                      />
                      <div className="mt-2 min-h-5 text-xs text-muted">
                        {getComponentOption(line.componentItemId)?.name ?? "No component selected"}
                      </div>
                      {activeComponentPicker === index ? (
                        <div className="absolute z-20 mt-2 max-h-64 w-full overflow-y-auto rounded-2xl border border-line/70 bg-surface shadow-panel">
                          {componentOptions
                            .filter((option) => {
                              const query = (componentSearchTerms[index] ?? "").trim().toLowerCase();
                              if (!query) {
                                return true;
                              }

                              return option.sku.toLowerCase().includes(query);
                            })
                            .slice(0, 12)
                            .map((option) => (
                              <button
                                key={option.id}
                                type="button"
                                onMouseDown={(event) => {
                                  event.preventDefault();
                                  updateBomLine(index, { ...line, componentItemId: option.id });
                                  updateComponentSearchTerm(index, option.sku);
                                  setActiveComponentPicker(null);
                                }}
                                title={option.name}
                                className="block w-full border-b border-line/50 px-4 py-2 text-left text-sm font-semibold text-text transition last:border-b-0 hover:bg-page/70"
                              >
                                {option.sku}
                              </button>
                            ))}
                          {componentOptions.filter((option) => {
                            const query = (componentSearchTerms[index] ?? "").trim().toLowerCase();
                            if (!query) {
                              return true;
                            }

                            return option.sku.toLowerCase().includes(query);
                          }).length === 0 ? (
                            <div className="px-2 py-2 text-sm text-muted">No matching components found.</div>
                          ) : null}
                        </div>
                      ) : null}
                    </div>
                  </label>
                  <label className="block">
                    <span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">Qty</span>
                    <input
                      type="number"
                      min={1}
                      step={1}
                      value={line.quantity}
                      onChange={(event) => updateBomLine(index, { ...line, quantity: Number.parseInt(event.target.value, 10) || 0 })}
                      className="w-full rounded-2xl border border-line/70 bg-surface px-2 py-2 text-text outline-none transition focus:border-brand"
                    />
                  </label>
                  <label className="block">
                    <span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">UOM</span>
                    <select
                      value={line.unitOfMeasure}
                      onChange={(event) => updateBomLine(index, { ...line, unitOfMeasure: event.target.value as InventoryBomLineInput["unitOfMeasure"] })}
                      className="w-full rounded-2xl border border-line/70 bg-surface px-2 py-2 text-text outline-none transition focus:border-brand"
                    >
                      {inventoryUnitOptions.map((option) => (
                        <option key={option.value} value={option.value}>
                          {option.label}
                        </option>
                      ))}
                    </select>
                  </label>
                  <label className="block">
                    <span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">Position</span>
                    <input
                      type="number"
                      min={0}
                      step={10}
                      value={line.position}
                      onChange={(event) => updateBomLine(index, { ...line, position: Number(event.target.value) })}
                      className="w-full rounded-2xl border border-line/70 bg-surface px-2 py-2 text-text outline-none transition focus:border-brand"
                    />
                  </label>
                  <div className="flex items-end">
                    <button
                      type="button"
                      onClick={() => removeBomLine(index)}
                      className="rounded-2xl border border-rose-400/40 px-2 py-2 text-sm font-semibold text-rose-700 dark:text-rose-300"
                    >
                      Remove
                    </button>
                  </div>
                </div>
                <label className="mt-4 block">
                  <span className="mb-2 block text-xs font-semibold uppercase tracking-[0.16em] text-muted">Notes</span>
                  <input
                    value={line.notes}
                    onChange={(event) => updateBomLine(index, { ...line, notes: event.target.value })}
                    className="w-full rounded-2xl border border-line/70 bg-surface px-2 py-2 text-text outline-none transition focus:border-brand"
                  />
                </label>
              </div>
            ))}
          </div>
        )}
        <div className="mt-6 flex flex-col gap-3 rounded-2xl border border-line/70 bg-page/70 px-2 py-2 sm:flex-row sm:items-center sm:justify-between">
          <span className="min-w-0 text-sm text-muted">{status}</span>
          <button
            type="submit"
            disabled={isSaving}
            className="rounded-2xl bg-brand px-2 py-2 text-sm font-semibold text-white disabled:cursor-not-allowed disabled:opacity-60"
          >
            {isSaving ? "Saving..." : mode === "create" ? "Create item" : "Save changes"}
          </button>
        </div>
      </section>
    </form>
  );
}
