import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { ArrowLeft, Plus, Trash2 } from 'lucide-react';
import { toast } from 'sonner';
import { Button } from '../ui/button';
import { Input } from '../ui/input';
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from '../ui/table';
import { SearchableSelect } from '../ui/searchable-select';
import { ImageUrlUpload } from '../ui/image-url-upload';
import { getLabelTemplate, updateLabelTemplate } from '../../services/labelTemplateService';
import { getProducts } from '../../services/productService';
import { getLabelTypes } from '../../services/labelTypeService';
import { skipCountForPage } from '../../lib/paginationQuery';
import type { ElementType, LabelElement, LabelTemplateDto, LabelType, Unit } from '../../types/labelTemplate';
import {
  appliedLocationToEditor,
  dataEntryColumnLabel,
  isDataEntryTableColumnElement,
  labelElementsToApiPayload,
  sortTemplateElementsForDisplay,
} from '../../types/labelTemplate';
import type { ProductDto } from '../../types/product';
import type { LabelTypeDto } from '../../types/labelType';

export type TemplateDataEntryRow = {
  id: string;
  productId: string;
  labelTypeId: string;
  /** elementId -> 管理端录入的关联/默认值（真正打印时输入仍在 App） */
  fieldValues: Record<string, string>;
};

function newRowId(): string {
  try {
    return crypto.randomUUID();
  } catch {
    return `row-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
  }
}

function DataEntryValueCell({
  elementType,
  value,
  onValueChange,
}: {
  elementType: ElementType;
  value: string;
  onValueChange: (next: string) => void;
}) {
  if (elementType === 'IMAGE') {
    return (
      <ImageUrlUpload
        value={value}
        onChange={onValueChange}
        uploadSubDir="label-template-data"
        oneImageOnly
        boxClassName="max-w-[160px]"
        hint="Upload stores full URL/path for save."
      />
    );
  }
  return (
    <Input
      value={value}
      onChange={(e) => onValueChange(e.target.value)}
      placeholder="—"
      className="h-10 border-gray-300"
    />
  );
}

export function LabelTemplateDataEntryView({
  templateCode,
  onBack,
}: {
  templateCode: string;
  onBack: () => void;
}) {
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [templateTitle, setTemplateTitle] = useState('');
  /** 详情接口完整模板，保存时随 templateProductDefaults 一并 PUT（接口 4.4） */
  const [templateDto, setTemplateDto] = useState<LabelTemplateDto | null>(null);
  const [printFields, setPrintFields] = useState<LabelElement[]>([]);
  const [products, setProducts] = useState<ProductDto[]>([]);
  const [types, setTypes] = useState<LabelTypeDto[]>([]);
  const [rows, setRows] = useState<TemplateDataEntryRow[]>([]);

  const productOptions = useMemo(
    () =>
      products.map((p) => {
        const label =
          (p.productName ?? p.productCode ?? '').trim() || p.id;
        return { value: p.id, label };
      }),
    [products],
  );

  const labelTypeOptions = useMemo(
    () =>
      types.map((t) => {
        const label =
          (t.typeName ?? t.typeCode ?? '').trim() || t.id;
        return { value: t.id, label };
      }),
    [types],
  );

  useEffect(() => {
    let cancelled = false;
    (async () => {
      setLoading(true);
      try {
        const [tpl, prodRes, typeRes] = await Promise.all([
          getLabelTemplate(templateCode),
          getProducts({ skipCount: skipCountForPage(1), maxResultCount: 500 }),
          getLabelTypes({ skipCount: skipCountForPage(1), maxResultCount: 500 }),
        ]);
        if (cancelled) return;
        const title =
          (tpl.templateName ?? tpl.name ?? '').trim() ||
          (tpl.templateCode ?? tpl.id ?? '').trim() ||
          templateCode;
        setTemplateTitle(title);
        const elements = sortTemplateElementsForDisplay(
          (tpl.elements ?? []) as LabelElement[],
        ).filter(isDataEntryTableColumnElement);
        setPrintFields(elements);
        setProducts(prodRes.items ?? []);
        setTypes(typeRes.items ?? []);
        setTemplateDto(tpl);

        const defaults = tpl.templateProductDefaults ?? [];
        const fromApi =
          defaults.length > 0
            ? [...defaults].sort((a, b) => (a.orderNum ?? 0) - (b.orderNum ?? 0))
            : [];

        if (fromApi.length > 0) {
          setRows(
            fromApi.map((d) => ({
              id: newRowId(),
              productId: d.productId,
              labelTypeId: d.labelTypeId,
              fieldValues: { ...d.defaultValues },
            })),
          );
        } else {
          setRows([
            {
              id: newRowId(),
              productId: '',
              labelTypeId: '',
              fieldValues: {},
            },
          ]);
        }
      } catch (e: unknown) {
        if (!cancelled) {
          toast.error('Failed to load template or options.', {
            description: e instanceof Error ? e.message : 'Please try again.',
          });
          setTemplateTitle(templateCode);
          setPrintFields([]);
          setRows([]);
          setTemplateDto(null);
        }
      } finally {
        if (!cancelled) setLoading(false);
      }
    })();
    return () => {
      cancelled = true;
    };
  }, [templateCode]);

  const addRow = useCallback(() => {
    setRows((prev) => [
      ...prev,
      { id: newRowId(), productId: '', labelTypeId: '', fieldValues: {} },
    ]);
  }, []);

  const removeRow = useCallback((id: string) => {
    setRows((prev) => (prev.length <= 1 ? prev : prev.filter((r) => r.id !== id)));
  }, []);

  const updateRow = useCallback((id: string, patch: Partial<TemplateDataEntryRow>) => {
    setRows((prev) =>
      prev.map((r) => (r.id === id ? { ...r, ...patch } : r)),
    );
  }, []);

  const setFieldValue = useCallback(
    (rowId: string, elementId: string, value: string) => {
      setRows((prev) =>
        prev.map((r) => {
          if (r.id !== rowId) return r;
          return {
            ...r,
            fieldValues: { ...r.fieldValues, [elementId]: value },
          };
        }),
      );
    },
    [],
  );

  const handleSave = useCallback(async () => {
    if (!templateDto) {
      toast.error('Template not loaded', { description: 'Please reload the page and try again.' });
      return;
    }
    const touched = rows.filter((r) => r.productId.trim() || r.labelTypeId.trim());
    const incomplete = touched.some(
      (r) => !r.productId.trim() || !r.labelTypeId.trim(),
    );
    if (incomplete) {
      toast.error('Product and label type required', {
        description:
          'Each row that you started must have both Product and Label type selected.',
      });
      return;
    }

    const validRows = rows.filter((r) => r.productId.trim() && r.labelTypeId.trim());
    const templateProductDefaults = validRows.map((r, i) => {
      const defaultValues: Record<string, string> = {};
      for (const f of printFields) {
        defaultValues[f.id] = r.fieldValues[f.id] ?? '';
      }
      return {
        productId: r.productId.trim(),
        labelTypeId: r.labelTypeId.trim(),
        defaultValues,
        orderNum: i + 1,
      };
    });

    const fullElements = sortTemplateElementsForDisplay(
      (templateDto.elements ?? []) as LabelElement[],
    );
    if (fullElements.length === 0) {
      toast.error('Template has no elements', { description: 'Cannot save this template.' });
      return;
    }

    const loc = appliedLocationToEditor(templateDto);
    setSaving(true);
    try {
      const updated = await updateLabelTemplate(templateCode, {
        id: templateDto.id,
        name: (templateDto.name ?? templateDto.templateName ?? '').trim() || templateCode,
        labelType: (templateDto.labelType ?? 'PRICE') as LabelType,
        unit: (templateDto.unit ?? 'inch') as Unit,
        width: Number(templateDto.width ?? 2),
        height: Number(templateDto.height ?? 2),
        appliedLocation: loc,
        showRuler: templateDto.showRuler ?? true,
        showGrid: templateDto.showGrid ?? true,
        state: templateDto.state ?? true,
        elements: labelElementsToApiPayload(fullElements),
        appliedLocationIds: loc === 'ALL' ? [] : (templateDto.appliedLocationIds ?? []),
        templateProductDefaults,
      });
      setTemplateDto(updated);
      toast.success('Saved', {
        description: 'Template product defaults were updated on the server.',
      });
    } catch (e: unknown) {
      toast.error('Save failed', {
        description: e instanceof Error ? e.message : 'Please try again.',
      });
    } finally {
      setSaving(false);
    }
  }, [templateCode, templateDto, rows, printFields]);

  return (
    <div className="h-full flex flex-col min-h-0">
      <div className="flex flex-wrap items-center gap-3 pb-4 border-b border-gray-200 shrink-0">
        <Button
          type="button"
          variant="outline"
          className="h-10 gap-2"
          onClick={onBack}
        >
          <ArrowLeft className="h-4 w-4" />
          Back
        </Button>
        <div className="flex-1 min-w-[200px]">
          <div className="text-xs font-medium text-gray-500 uppercase tracking-wide">
            Label template
          </div>
          <h2 className="text-lg font-semibold text-gray-900 truncate" title={templateTitle}>
            {templateTitle}
          </h2>
        </div>
        <div className="flex items-center gap-2">
          <Button type="button" variant="outline" className="h-10 gap-1" onClick={addRow}>
            <Plus className="h-4 w-4" />
            Add row
          </Button>
          <Button
            type="button"
            className="h-10 bg-blue-600 hover:bg-blue-700"
            onClick={() => void handleSave()}
            disabled={saving || loading || !templateDto}
          >
            {saving ? 'Saving…' : 'Save'}
          </Button>
        </div>
      </div>

      <p className="text-sm text-gray-600 py-3 shrink-0">
        Bind product and label type per row. Values are saved with the template (edit API) as{' '}
        <span className="font-medium">templateProductDefaults</span> (interface doc section 4.4). Only{' '}
        <span className="font-medium">FIXED</span> fields appear here.{' '}
        <span className="font-medium">AUTO_DB</span> and <span className="font-medium">PRINT_INPUT</span>{' '}
        are resolved at print time in the app. Column headers use{' '}
        <span className="font-medium">elementName</span>.
      </p>

      <div className="flex-1 min-h-0 overflow-auto rounded-md border bg-white shadow-sm">
        {loading ? (
          <div className="p-10 text-center text-sm text-gray-500">Loading…</div>
        ) : printFields.length === 0 ? (
          <div className="p-10 text-center text-sm text-gray-600">
            No <span className="font-medium">FIXED</span> elements in this template (or none besides
            blanks). AUTO_DB / PRINT_INPUT columns are hidden here by design.
          </div>
        ) : (
          <Table>
            <TableHeader>
              <TableRow className="bg-gray-50 hover:bg-gray-50">
                <TableHead className="font-bold text-gray-900 w-[200px] min-w-[160px]">
                  Product
                </TableHead>
                <TableHead className="font-bold text-gray-900 w-[180px] min-w-[140px]">
                  Label type
                </TableHead>
                {printFields.map((f) => (
                  <TableHead
                    key={f.id}
                    className="font-bold text-gray-900 min-w-[120px] whitespace-nowrap"
                    title={f.id}
                  >
                    {dataEntryColumnLabel(f)}
                  </TableHead>
                ))}
                <TableHead className="w-[72px] text-center font-bold text-gray-900"> </TableHead>
              </TableRow>
            </TableHeader>
            <TableBody>
              {rows.map((row) => (
                <TableRow key={row.id} className="hover:bg-gray-50">
                  <TableCell className="align-top py-2">
                    <SearchableSelect
                      value={row.productId}
                      onValueChange={(v) => updateRow(row.id, { productId: v })}
                      options={productOptions}
                      placeholder="Select product"
                      searchPlaceholder="Search product…"
                    />
                  </TableCell>
                  <TableCell className="align-top py-2">
                    <SearchableSelect
                      value={row.labelTypeId}
                      onValueChange={(v) => updateRow(row.id, { labelTypeId: v })}
                      options={labelTypeOptions}
                      placeholder="Select label type"
                      searchPlaceholder="Search type…"
                    />
                  </TableCell>
                  {printFields.map((f) => (
                    <TableCell key={f.id} className="align-top py-2">
                      <DataEntryValueCell
                        elementType={f.type}
                        value={row.fieldValues[f.id] ?? ''}
                        onValueChange={(v) => setFieldValue(row.id, f.id, v)}
                      />
                    </TableCell>
                  ))}
                  <TableCell className="text-center align-top py-2">
                    <Button
                      type="button"
                      variant="ghost"
                      size="icon"
                      className="h-9 w-9 text-red-600 hover:text-red-700 hover:bg-red-50"
                      aria-label="Remove row"
                      onClick={() => removeRow(row.id)}
                      disabled={rows.length <= 1}
                    >
                      <Trash2 className="h-4 w-4" />
                    </Button>
                  </TableCell>
                </TableRow>
              ))}
            </TableBody>
          </Table>
        )}
      </div>
    </div>
  );
}
