import { useState, useEffect, useCallback, useRef } from "react";
import axios from "axios";
import { useForm, Controller } from "react-hook-form";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Textarea } from "@/components/ui/textarea";
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { Loader2, X, Copy, Maximize2, Minus, Store, Terminal, ExternalLink } from "lucide-react";
import { submitProductEdit, type ImageChanges } from "@/services/productEditor";
import { EditableComboboxField } from "./EditableComboboxField";
import { EditableInput } from "./EditableInput";
import { EditableMultiSelect } from "./EditableMultiSelect";
import { ImageManager, MiniImagePreview } from "./ImageManager";
import type {
  SearchProduct,
  FieldOptions,
  FieldOption,
  LineOption,
  ProductImage,
  ProductFormValues,
} from "./types";

// Simple in-memory cache for lines/sublines to avoid duplicate requests across forms
const linesCache = new Map<string, Promise<LineOption[]>>();
const sublinesCache = new Map<string, Promise<LineOption[]>>();

function fetchLinesCached(companyId: string, signal?: AbortSignal): Promise<LineOption[]> {
  const cached = linesCache.get(companyId);
  if (cached) return cached;
  const p = axios
    .get(`/api/import/product-lines/${companyId}`, { signal })
    .then((res) => res.data as LineOption[])
    .catch(() => {
      linesCache.delete(companyId);
      return [] as LineOption[];
    });
  linesCache.set(companyId, p);
  return p;
}

function fetchSublinesCached(lineId: string, signal?: AbortSignal): Promise<LineOption[]> {
  const cached = sublinesCache.get(lineId);
  if (cached) return cached;
  const p = axios
    .get(`/api/import/sublines/${lineId}`, { signal })
    .then((res) => res.data as LineOption[])
    .catch(() => {
      sublinesCache.delete(lineId);
      return [] as LineOption[];
    });
  sublinesCache.set(lineId, p);
  return p;
}

// --- Field configuration types ---

type FieldType = "input" | "combobox" | "multiselect" | "textarea";

interface FieldConfig {
  key: keyof ProductFormValues;
  label: string;
  type: FieldType;
  placeholder?: string;
  searchPlaceholder?: string;
  maxLength?: number;
  rows?: number;
  copyable?: boolean;
  /** For combobox: key into fieldOptions, or "lines"/"sublines" for dynamic */
  optionsKey?: keyof FieldOptions | "lines" | "sublines";
  /** For combobox: disable when this other field is empty */
  disabledUnless?: keyof ProductFormValues;
  /** For multiselect colors field */
  showColors?: boolean;
  /** Format value for display (editing shows raw value) */
  formatDisplay?: (val: string) => string;
}

interface FieldGroup {
  label?: string;
  cols: number;
  fields: FieldConfig[];
}

// --- Layout modes ---

export type LayoutMode = "full" | "minimal" | "shop" | "backend";

export const LAYOUT_ICONS: { mode: LayoutMode; label: string; icon: React.ComponentType<{ className?: string }> }[] = [
  { mode: "full", label: "Full", icon: Maximize2 },
  { mode: "minimal", label: "Minimal", icon: Minus },
  { mode: "shop", label: "Shop", icon: Store },
  { mode: "backend", label: "Backend", icon: Terminal },
];

// --- Field registry (all available fields) ---

const F: Record<string, FieldConfig> = {
  company:      { key: "company", label: "Company", type: "combobox", optionsKey: "companies", searchPlaceholder: "Search companies..." },
  line:         { key: "line", label: "Line", type: "combobox", optionsKey: "lines", searchPlaceholder: "Search lines...", disabledUnless: "company" },
  subline:      { key: "subline", label: "Subline", type: "combobox", optionsKey: "sublines", searchPlaceholder: "Search sublines...", disabledUnless: "line" },
  artist:       { key: "artist", label: "Artist", type: "combobox", optionsKey: "artists", searchPlaceholder: "Search artists..." },
  tax_cat:      { key: "tax_cat", label: "Tax Cat", type: "combobox", optionsKey: "taxCategories" },
  ship:         { key: "ship_restrictions", label: "Shipping", type: "combobox", optionsKey: "shippingRestrictions" },
  msrp:         { key: "msrp", label: "MSRP", type: "input" },
  cost:         { key: "cost_each", label: "Cost", type: "input", formatDisplay: (v) => { const n = parseFloat(v); return isNaN(n) ? v : n.toFixed(2); } },
  min_qty:      { key: "qty_per_unit", label: "Min Qty", type: "input" },
  case_qty:     { key: "case_qty", label: "Case Pack", type: "input" },
  weight:       { key: "weight", label: "Weight (oz)", type: "input" },
  length:       { key: "length", label: "Length (in)", type: "input" },
  width:        { key: "width", label: "Width (in)", type: "input" },
  height:       { key: "height", label: "Height (in)", type: "input" },
  size_cat:     { key: "size_cat", label: "Size Cat", type: "combobox", optionsKey: "sizes" },
  coo:          { key: "coo", label: "Country of Origin", type: "input", placeholder: "2-letter code", maxLength: 2 },
  hts_code:     { key: "hts_code", label: "HTS Code", type: "input" },
  categories:   { key: "categories", label: "Categories", type: "multiselect", optionsKey: "categories", searchPlaceholder: "Search categories..." },
  themes:       { key: "themes", label: "Themes", type: "multiselect", optionsKey: "themes", searchPlaceholder: "Search themes..." },
  colors:       { key: "colors", label: "Colors", type: "multiselect", optionsKey: "colors", searchPlaceholder: "Search colors...", showColors: true },
  supplier:     { key: "supplier", label: "Supplier", type: "combobox", optionsKey: "suppliers", searchPlaceholder: "Search suppliers..." },
  description:  { key: "description", label: "Description", type: "textarea", rows: 8 },
  priv_notes:   { key: "priv_notes", label: "Private Notes", type: "textarea", rows: 2 },
};

// --- Per-mode layouts with fields combined into sensible rows ---

interface ModeLayout {
  /** Number of leading groups to render beside images (max cols 2 in sidebar) */
  sidebarGroups: number;
  /** Max visible rows in the image grid */
  imageRows?: number;
  /** Override description textarea rows */
  descriptionRows?: number;
  groups: FieldGroup[];
}

const MODE_LAYOUTS: Record<LayoutMode, ModeLayout> = {
  full: {
    sidebarGroups: 3,
    groups: [
      { label: "Taxonomy", cols: 2, fields: [F.supplier,F.company, F.line, F.subline] },
      { cols: 2, fields: [F.artist, F.size_cat] },
      { label: "Description", cols: 1, fields: [F.description] },
      { label: "Pricing", cols: 4, fields: [F.msrp, F.cost, F.min_qty, F.case_qty] },
      { label: "Dimensions", cols: 4, fields: [F.weight, F.length, F.width, F.height] },
      { cols: 4, fields: [ F.tax_cat, F.ship,F.coo, F.hts_code] },
      { label: "Classification", cols: 3, fields: [F.categories, F.themes, F.colors] },
      { label: "Notes", cols: 1, fields: [F.priv_notes] },
    ],
  },
  shop: {
    sidebarGroups: 3,
    descriptionRows: 8,
    groups: [
      { label: "Taxonomy", cols: 2, fields: [F.company, F.msrp, F.line, F.subline] },
      { cols: 2, fields: [F.artist, F.size_cat] },
      { label: "Description", cols: 1, fields: [F.description] },
      { label: "Classification", cols: 3, fields: [F.categories, F.themes, F.colors] },

    ],
  },
  backend: {
    sidebarGroups: 5,
    groups: [
      { label: "Pricing", cols: 2, fields: [F.supplier, F.min_qty, F.cost, F.msrp] },
      { cols: 3, fields: [F.case_qty, F.size_cat, F.weight] },
      { label: "Dimensions", cols: 3, fields: [ F.length, F.width, F.height] },
      { cols: 2, fields: [F.tax_cat, F.ship, F.coo, F.hts_code] },
      { label: "Notes", cols: 1, fields: [F.priv_notes] },

    ],
  },
  minimal: {
    sidebarGroups: 3,
    imageRows: 2.2,
    descriptionRows: 5,
    groups: [
      { cols: 2, fields: [F.company, F.msrp, F.line, F.subline] },
      { label: "Description", cols: 1, fields: [F.description] },
    ],
  },
};

export function ProductEditForm({
  product,
  fieldOptions,
  layoutMode,
  onClose,
}: {
  product: SearchProduct;
  fieldOptions: FieldOptions;
  layoutMode: LayoutMode;
  onClose: () => void;
}) {
  const [lineOptions, setLineOptions] = useState<LineOption[]>([]);
  const [sublineOptions, setSublineOptions] = useState<LineOption[]>([]);
  const [productImages, setProductImages] = useState<ProductImage[]>([]);
  const [isLoadingImages, setIsLoadingImages] = useState(false);
  const [isSubmitting, setIsSubmitting] = useState(false);

  const originalValuesRef = useRef<ProductFormValues | null>(null);
  const originalImagesRef = useRef<ProductImage[]>([]);

  const {
    register,
    control,
    handleSubmit,
    reset,
    watch,
    formState: { dirtyFields },
  } = useForm<ProductFormValues>();

  const watchCompany = watch("company");
  const watchLine = watch("line");

  // Populate form on mount
  useEffect(() => {
    const formValues: ProductFormValues = {
      name: product.title ?? "",
      company: String(product.brand_id ?? ""),
      line: String(product.line_id ?? ""),
      subline: String(product.subline_id ?? ""),
      supplier: String(product.supplier ?? ""),
      upc: product.barcode ?? "",
      item_number: product.sku ?? "",
      supplier_no: product.vendor_reference ?? "",
      notions_no: product.notions_reference ?? "",
      msrp: String(product.regular_price ?? ""),
      cost_each: String(product.cost_price ?? ""),
      qty_per_unit: String(product.moq ?? ""),
      case_qty: String(product.case_qty ?? ""),
      tax_cat: String(product.tax_code ?? ""),
      artist: String(product.artist_id ?? ""),
      weight: product.weight?.toString() ?? "",
      length: product.length?.toString() ?? "",
      width: product.width?.toString() ?? "",
      height: product.height?.toString() ?? "",
      ship_restrictions: product.shipping_restrictions ?? "",
      coo: product.country_of_origin ?? "",
      hts_code: product.harmonized_tariff_code ?? "",
      size_cat: product.size_cat ?? "",
      description: product.description ?? "",
      priv_notes: "",
      categories: [],
      themes: [],
      colors: [],
    };

    originalValuesRef.current = { ...formValues };
    reset(formValues);

    // Fetch images and categories with abort support
    const controller = new AbortController();
    const { signal } = controller;

    setIsLoadingImages(true);
    axios
      .get(`/api/import/product-images/${product.pid}`, { signal })
      .then((res) => {
        setProductImages(res.data);
        originalImagesRef.current = res.data;
      })
      .catch((e) => { if (!axios.isCancel(e)) toast.error("Failed to load product images"); })
      .finally(() => setIsLoadingImages(false));

    axios
      .get(`/api/import/product-categories/${product.pid}`, { signal })
      .then((res) => {
        const cats: string[] = [];
        const themes: string[] = [];
        for (const item of res.data) {
          const t = Number(item.type);
          if (t >= 10 && t <= 13) cats.push(String(item.value));
          else if (t >= 20 && t <= 21) themes.push(String(item.value));
        }
        const updatedValues = {
          ...formValues,
          categories: cats,
          themes,
        };
        originalValuesRef.current = { ...updatedValues };
        reset(updatedValues);
      })
      .catch(() => {
        // Non-critical — just leave arrays empty
      });

    return () => controller.abort();
  }, [product, reset]);

  // Load lines when company changes (cached across forms)
  useEffect(() => {
    if (!watchCompany) {
      setLineOptions([]);
      return;
    }
    const controller = new AbortController();
    fetchLinesCached(watchCompany, controller.signal).then(setLineOptions);
    return () => controller.abort();
  }, [watchCompany]);

  // Load sublines when line changes (cached across forms)
  useEffect(() => {
    if (!watchLine) {
      setSublineOptions([]);
      return;
    }
    const controller = new AbortController();
    fetchSublinesCached(watchLine, controller.signal).then(setSublineOptions);
    return () => controller.abort();
  }, [watchLine]);

  const computeImageChanges = useCallback((): ImageChanges | null => {
    const original = originalImagesRef.current;
    const current = productImages;

    const originalIds = original.map((img) => img.iid);
    const currentIds = current.map((img) => img.iid);

    const deleted = originalIds.filter((id) => !currentIds.includes(id)) as number[];
    const hidden = current.filter((img) => img.hidden).map((img) => img.iid).filter((id): id is number => typeof id === "number");
    const added: Record<string, string> = {};
    for (const img of current) {
      if (img.isNew && img.imageUrl) {
        added[String(img.iid)] = img.imageUrl;
      }
    }

    const order = current.map((img) => img.iid);

    const originalHidden = original.filter((img) => img.hidden).map((img) => img.iid);
    const orderChanged = JSON.stringify(order.filter((id) => typeof id === "number")) !== JSON.stringify(originalIds);
    const hiddenChanged = JSON.stringify([...hidden].sort()) !== JSON.stringify([...(originalHidden as number[])].sort());
    const hasDeleted = deleted.length > 0;
    const hasAdded = Object.keys(added).length > 0;

    if (!orderChanged && !hiddenChanged && !hasDeleted && !hasAdded) {
      return null;
    }

    return { order, hidden, deleted, added };
  }, [productImages]);

  const onSubmit = useCallback(
    async (data: ProductFormValues) => {
      if (!originalValuesRef.current) return;

      const original = originalValuesRef.current;
      const changes: Record<string, unknown> = {};

      for (const key of Object.keys(data) as (keyof ProductFormValues)[]) {
        const cur = data[key];
        const orig = original[key];
        if (Array.isArray(cur) && Array.isArray(orig)) {
          if (JSON.stringify([...cur].sort()) !== JSON.stringify([...orig].sort())) {
            changes[key] = cur;
          }
        } else if (cur !== orig) {
          changes[key] = cur;
        }
      }

      const imageChanges = computeImageChanges();

      if (Object.keys(changes).length === 0 && !imageChanges) {
        toast.info("No changes to submit");
        return;
      }

      setIsSubmitting(true);
      try {
        const result = await submitProductEdit({
          pid: product.pid,
          changes,
          environment: "prod",
          imageChanges: imageChanges ?? undefined,
        });

        if (result.success) {
          toast.success("Product updated successfully");
          originalValuesRef.current = { ...data };
          originalImagesRef.current = [...productImages];
          reset(data);
        } else {
          const errorDetail = Array.isArray(result.error)
            ? result.error.filter((e) => e !== "Errors").join("; ")
            : typeof result.error === "string"
              ? result.error
              : null;
          toast.error(errorDetail || result.message || "Failed to update product");
        }
      } catch (err) {
        toast.error(
          err instanceof Error ? err.message : "Failed to update product"
        );
      } finally {
        setIsSubmitting(false);
      }
    },
    [product.pid, reset, computeImageChanges, productImages]
  );

  // Resolve options for a field config
  const getOptions = useCallback(
    (optionsKey?: string): FieldOption[] => {
      if (!optionsKey) return [];
      if (optionsKey === "lines") return lineOptions;
      if (optionsKey === "sublines") return sublineOptions;
      return (fieldOptions[optionsKey as keyof FieldOptions] as FieldOption[]) ?? [];
    },
    [fieldOptions, lineOptions, sublineOptions]
  );

  const hasImageChanges = computeImageChanges() !== null;
  const changedCount = Object.keys(dirtyFields).length;

  const renderFieldGroup = (group: FieldGroup, gi: number) => (
    <div
      key={gi}
      className="grid gap-x-2 gap-y-2 p-1 rounded-md"
      style={{ gridTemplateColumns: `repeat(${group.cols}, minmax(0, 1fr))` }}
    >
      {group.fields.map((fc) => {
        if (fc.type === "input") {
          return (
            <Controller
              key={fc.key}
              name={fc.key}
              control={control}
              render={({ field }) => (
                <EditableInput
                  label={fc.label}
                  value={field.value as string}
                  onChange={field.onChange}
                  onBlur={field.onBlur}
                  placeholder={fc.placeholder ?? "—"}
                  maxLength={fc.maxLength}
                  copyable={fc.copyable}
                  formatDisplay={fc.formatDisplay}
                />
              )}
            />
          );
        }
        if (fc.type === "combobox") {
          return (
            <Controller
              key={fc.key}
              name={fc.key}
              control={control}
              render={({ field }) => (
                <EditableComboboxField
                  label={fc.label}
                  options={getOptions(fc.optionsKey)}
                  value={field.value as string}
                  onChange={field.onChange}
                  placeholder="—"
                  searchPlaceholder={fc.searchPlaceholder}
                  disabled={fc.disabledUnless ? !watch(fc.disabledUnless) : false}
                />
              )}
            />
          );
        }
        if (fc.type === "multiselect") {
          return (
            <Controller
              key={fc.key}
              name={fc.key}
              control={control}
              render={({ field }) => (
                <EditableMultiSelect
                  label={fc.label}
                  options={getOptions(fc.optionsKey)}
                  value={(field.value as string[]) ?? []}
                  onChange={field.onChange}
                  placeholder="—"
                  searchPlaceholder={fc.searchPlaceholder}
                  showColors={fc.showColors}
                />
              )}
            />
          );
        }
        if (fc.type === "textarea") {
          return (
            <div key={fc.key} className="col-span-full flex flex-col gap-0.5 rounded-md border border-muted-foreground/50 bg-transparent px-3 py-1 text-sm hover:border-input hover:bg-muted/50 transition-colors">
              <span className="text-muted-foreground text-xs shrink-0">{fc.label}</span>
              <Textarea {...register(fc.key)} rows={(fc.key === "description" && MODE_LAYOUTS[layoutMode].descriptionRows) || fc.rows || 3} className="border-0 p-0 h-auto shadow-none focus-visible:ring-0 resize-y text-sm min-h-0" />
            </div>
          );
        }
        return null;
      })}
    </div>
  );

  return (
    <Card>
      <CardHeader>
        <div className="flex items-start justify-between">
          <div className="flex-1 min-w-0 flex items-center gap-1">
            <div className="flex-1 min-w-0">
              <Controller
                name="name"
                control={control}
                render={({ field }) => (
                  <EditableInput
                    value={field.value}
                    onChange={field.onChange}
                    onBlur={field.onBlur}
                    placeholder="Product name"
                    className="text-base font-semibold"
                    inputClassName="text-base font-semibold"
                  />
                )}
              />
            </div>
            <Tooltip>
              <TooltipTrigger asChild>
                <Button
                  variant="outline"
                  size="icon"
                  asChild
                >
                  <a
                    href={`https://backend.acherryontop.com/product/${product.pid}`}
                    target="_blank"
                    rel="noopener noreferrer"
                  >
                    <ExternalLink className="h-5 w-5" />
                  </a>
                </Button>
              </TooltipTrigger>
              <TooltipContent side="bottom">View in Backend</TooltipContent>
            </Tooltip>
          </div>
          <div className="flex items-center justify-end mb-3 ml-1">
          <Tooltip>
            <TooltipTrigger asChild>
              <Button variant="outline" size="icon" onClick={onClose}>
                <X className="h-5 w-5" />
              </Button>
            </TooltipTrigger>
            <TooltipContent side="bottom">Hide this product</TooltipContent>
          </Tooltip>
        </div>
        </div>
        <div className="flex flex-wrap gap-2 items-center justify-start">
              <Badge
                variant="secondary"
                className="gap-1 cursor-pointer hover:bg-muted text-xs px-2.5 h-[22px] font-normal"
                onClick={() => {
                  navigator.clipboard.writeText(String(product.pid));
                  toast.success("Copied PID");
                }}
              >
                <span className="text-muted-foreground text-xs">PID</span> {product.pid}
                <Copy className="h-3 w-3 opacity-50" />
              </Badge>
              {(["item_number", "upc", "supplier_no", "notions_no"] as const).map((key) => (
                <Controller
                  key={key}
                  name={key}
                  control={control}
                  render={({ field }) => (
                    <EditableInput
                      label={{ item_number: "Item #", upc: "UPC", supplier_no: "Supplier #", notions_no: "Notions #" }[key]}
                      value={field.value as string}
                      onChange={field.onChange}
                      onBlur={field.onBlur}
                      placeholder="—"
                      copyable
                      alwaysShowCopy
                      className="w-auto border-none py-0 px-2.5 text-xs h-[22px] rounded-full bg-secondary hover:bg-muted"
                      inputClassName="text-xs"
                    />
                  )}
                />
              ))}
            </div>
      </CardHeader>
      <CardContent>
       
        <form onSubmit={handleSubmit(onSubmit)} className="space-y-1">
          {/* Images + sidebar fields */}
          <div className="flex gap-2">
            <div className="shrink-0">
              {layoutMode === "minimal" ? (
                <MiniImagePreview images={productImages} isLoading={isLoadingImages} />
              ) : (
                <ImageManager
                  images={productImages}
                  setImages={setProductImages}
                  isLoading={isLoadingImages}
                  maxRows={MODE_LAYOUTS[layoutMode].imageRows}
                />
              )}
            </div>
            {MODE_LAYOUTS[layoutMode].sidebarGroups > 0 && (
              <div className="flex-1 min-w-0 space-y-1">
                {MODE_LAYOUTS[layoutMode].groups.slice(0, MODE_LAYOUTS[layoutMode].sidebarGroups).map((group, gi) =>
                  renderFieldGroup(group, gi)
                )}
              </div>
            )}
          </div>

          {/* Remaining field groups */}
          {MODE_LAYOUTS[layoutMode].groups.slice(MODE_LAYOUTS[layoutMode].sidebarGroups).map((group, gi) =>
            renderFieldGroup(group, gi + MODE_LAYOUTS[layoutMode].sidebarGroups)
          )}

          {/* Submit */}
          <div className="flex items-center justify-end gap-3 pt-2">
            <Button
              type="button"
              variant="outline"
              size="sm"
              onClick={() => {
                if (originalValuesRef.current) {
                  reset(originalValuesRef.current);
                }
              }}
            >
              Reset Changes
            </Button>
            <Button
              type="submit"
              disabled={isSubmitting || (changedCount === 0 && !hasImageChanges)}
              size="sm"
            >
              {isSubmitting && (
                <Loader2 className="mr-2 h-4 w-4 animate-spin" />
              )}
              Submit{" "}
              {changedCount > 0 || hasImageChanges
                ? `(${changedCount} field${changedCount !== 1 ? "s" : ""}${hasImageChanges ? " + images" : ""})`
                : ""}
            </Button>
          </div>
        </form>
      </CardContent>
    </Card>
  );
}
