import React, { useState, useMemo, useEffect } from 'react';
import { LabelTemplate, PaperConfig, ImportData, RecordRow, ExportRangeConfig, CutLineConfig } from './types';
import {
  stripTemplateForStorage,
  normalizeTemplate,
  DEFAULT_PAPER_CONFIG,
  DEFAULT_EXPORT_RANGE,
  DEFAULT_CUT_LINE_CONFIG,
  exportRangeEquals,
  buildPrintablePages,
  extractTemplateVariables,
  buildAutoVariableMapping,
  applyRowVariableMapping,
  type PrintableLabel,
} from './utils';
import { LabelDesigner } from './components/LabelDesigner';
import { PropSidebar } from './components/PropSidebar';
import { ExportSidebar } from './components/ExportSidebar';
import { MobileExportView } from './components/MobileExportView';
import { LayoutPreview } from './components/PreviewGrid';
import { CanvasLabelImage } from './components/CanvasLabelImage';
import { renderLabelToDataUrl } from './labelRenderer';
import { exportLabelsPdfAsync, type PdfExportProgress } from './pdfExport';
import { useIsMobile } from './hooks/useIsMobile';
import { useAppDialog } from './components/AppDialog';
import {
  FileDown,
  Code,
  Wand2,
  Loader2,
  Plus,
  Download,
  Upload,
  Trash2,
  X,
} from 'lucide-react';

const TEMPLATE_PREVIEW_MAX_W = 220;
const TEMPLATE_PREVIEW_MAX_H = 132;

const EMPTY_TEMPLATE_PLACEHOLDER: LabelTemplate = {
  id: '__placeholder__',
  name: '',
  width: 70,
  height: 40,
  elements: [],
  paper: DEFAULT_PAPER_CONFIG,
  cutLine: DEFAULT_CUT_LINE_CONFIG,
};

function fitTemplatePreviewSize(widthMm: number, heightMm: number) {
  const scale = Math.min(
    TEMPLATE_PREVIEW_MAX_W / widthMm,
    TEMPLATE_PREVIEW_MAX_H / heightMm
  );
  return {
    displayWidthPx: widthMm * scale,
    displayHeightPx: heightMm * scale,
  };
}

export default function App() {
  const { showAlert, showConfirm } = useAppDialog();

  // --- 1. Templates Storage & Initial States ---
  const [templates, setTemplates] = useState<LabelTemplate[]>(() => {
    try {
      const saved = localStorage.getItem('label_templates_list_v2');
      if (saved) {
        const parsed = JSON.parse(saved);
        if (Array.isArray(parsed)) {
          return parsed.map((t: LabelTemplate) => normalizeTemplate(t));
        }
      }
    } catch (e) {}
    return [];
  });

  const [selectedTemplateId, setSelectedTemplateId] = useState<string>(() => {
    try {
      const savedList = localStorage.getItem('label_templates_list_v2');
      const savedId = localStorage.getItem('selected_label_template_id_v2');
      if (!savedList || !savedId) return '';
      const parsed = JSON.parse(savedList);
      if (Array.isArray(parsed) && parsed.some((t: LabelTemplate) => t.id === savedId)) {
        return savedId;
      }
    } catch (e) {}
    return '';
  });

  const hasTemplates = templates.length > 0;

  const activeTemplate = useMemo(() => {
    if (!hasTemplates) return null;
    return templates.find((t) => t.id === selectedTemplateId) ?? templates[0];
  }, [templates, selectedTemplateId, hasTemplates]);

  const workingTemplate = activeTemplate ?? EMPTY_TEMPLATE_PLACEHOLDER;

  // --- 2. Workflow Step Manager ---
  // Step 1: 'template-select' (Templates select/import + Associate excel data sources)
  // Step 2: 'template-design' (Visual designer workspace canvas)
  // Step 3: 'print-view' (Final pagination & print setting alignments grid)
  const [workflowStep, setWorkflowStep] = useState<'template-select' | 'template-design' | 'print-view'>('template-select');

  // --- 3. 排版导出会话数据（不持久化，每次进入排版页重新上传） ---
  const [importData, setImportData] = useState<ImportData | null>(null);
  const [variableColumnMapping, setVariableColumnMapping] = useState<Record<string, string>>({});
  const [previewSnapshot, setPreviewSnapshot] = useState<{
    pages: (PrintableLabel | null)[][];
    gridCols: number;
    labelsPerPage: number;
    totalPages: number;
    selectedCount: number;
    paper: PaperConfig;
    exportRange: ExportRangeConfig;
  } | null>(null);
  const [draftExportRange, setDraftExportRange] = useState<ExportRangeConfig>(DEFAULT_EXPORT_RANGE);
  const [appliedExportData, setAppliedExportData] = useState<{
    fileName: string;
    currentSheet: string;
    rows: RecordRow[];
    mapping: Record<string, string>;
    exportRange: ExportRangeConfig;
  } | null>(null);
  const [previewLayoutStale, setPreviewLayoutStale] = useState(false);
  const isMobile = useIsMobile();

  const [pdfGenerating, setPdfGenerating] = useState(false);
  const [pdfProgress, setPdfProgress] = useState<PdfExportProgress>({
    done: 0,
    total: 0,
    page: 0,
    totalPages: 0,
    phase: 'render',
  });

  // --- 5. Selection and Active item states ---
  const [selectedElementIds, setSelectedElementIds] = useState<string[]>([]);
  const [activeRowIndex, setActiveRowIndex] = useState<number>(0);
  // Modal / Inline input values for template creations
  const [showAddTmplForm, setShowAddTmplForm] = useState<boolean>(false);
  const [newTmplName, setNewTmplName] = useState<string>('');
  const [newTmplW, setNewTmplW] = useState<number>(75);
  const [newTmplH, setNewTmplH] = useState<number>(45);

  const paper = workingTemplate.paper ?? DEFAULT_PAPER_CONFIG;
  const cutLine = workingTemplate.cutLine ?? DEFAULT_CUT_LINE_CONFIG;

  // Save template list changes（不将完整行数据写入模板列表，避免 localStorage 膨胀）
  const saveTemplatesToStorage = (updatedList: LabelTemplate[]) => {
    setTemplates(updatedList);
    try {
      const stripped = updatedList.map(stripTemplateForStorage);
      localStorage.setItem('label_templates_list_v2', JSON.stringify(stripped));
    } catch (e) {}
  };

  // Modify active template elements
  const handleTemplateChange = (updated: LabelTemplate) => {
    const updatedList = templates.map(t => t.id === updated.id ? updated : t);
    saveTemplatesToStorage(updatedList);
  };

  // Save active template selected state and sync its dataset
  const handleSelectTemplate = (id: string) => {
    setSelectedTemplateId(id);
    setSelectedElementIds([]);
    try {
      localStorage.setItem('selected_label_template_id_v2', id);
    } catch (e) {}

    setActiveRowIndex(0);
  };

  useEffect(() => {
    if (!hasTemplates) {
      if (selectedTemplateId) setSelectedTemplateId('');
      if (workflowStep !== 'template-select') setWorkflowStep('template-select');
      return;
    }
    if (!templates.some((t) => t.id === selectedTemplateId)) {
      handleSelectTemplate(templates[0].id!);
    }
  }, [hasTemplates, templates, selectedTemplateId, workflowStep]);

  const handlePaperChange = (updated: PaperConfig) => {
    if (!activeTemplate) return;
    handleTemplateChange({ ...activeTemplate, paper: updated });
  };

  const handleCutLineChange = (next: CutLineConfig) => {
    if (!activeTemplate) return;
    handleTemplateChange({ ...activeTemplate, cutLine: next });
  };

  const openPrintView = (templateId?: string) => {
    if (!hasTemplates) return;
    if (templateId) {
      handleSelectTemplate(templateId);
    }
    setImportData(null);
    setVariableColumnMapping({});
    setPreviewSnapshot(null);
    setAppliedExportData(null);
    setPreviewLayoutStale(false);
    setActiveRowIndex(0);
    setDraftExportRange(DEFAULT_EXPORT_RANGE);
    setWorkflowStep('print-view');
  };

  const handleDataLoaded = (data: ImportData) => {
    setImportData(data);
    setPreviewSnapshot(null);
    setAppliedExportData(null);
    setPreviewLayoutStale(false);
    setActiveRowIndex(0);
    setDraftExportRange(DEFAULT_EXPORT_RANGE);
    if (!activeTemplate) return;
    const vars = extractTemplateVariables(activeTemplate);
    setVariableColumnMapping(buildAutoVariableMapping(vars, data.columns));
  };

  const handleClearData = () => {
    setImportData(null);
    setVariableColumnMapping({});
    setPreviewSnapshot(null);
    setAppliedExportData(null);
    setPreviewLayoutStale(false);
    setActiveRowIndex(0);
    setDraftExportRange(DEFAULT_EXPORT_RANGE);
  };

  const handleMappingChange = (mapping: Record<string, string>) => {
    setVariableColumnMapping(mapping);
  };

  // Add customized new template
  const handleAddTemplateSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!newTmplName.trim()) {
      await showAlert('请先输入合法的模板名', { variant: 'warning' });
      return;
    }
    const newId = `custom_tmpl_${Date.now()}`;
    const newTmpl: LabelTemplate = {
      id: newId,
      name: `${newTmplName} (${newTmplW}x${newTmplH}mm)`,
      width: Math.max(10, Number(newTmplW) || 70),
      height: Math.max(10, Number(newTmplH) || 40),
      elements: [
        {
          id: `desc_welcome`,
          type: 'text',
          name: '主文字内容',
          x: 5,
          y: 5,
          width: Math.max(10, newTmplW - 10),
          height: 10,
          content: '请插入绑定的文本内容 {货位编号}',
          fontSize: 12,
          textAlign: 'center',
          fontWeight: 'bold',
          barcodeFormat: 'CODE128',
          showText: false,
          fontFamily: 'sans'
        }
      ],
      paper: DEFAULT_PAPER_CONFIG,
      cutLine: DEFAULT_CUT_LINE_CONFIG,
    };

    const list = [...templates, newTmpl];
    saveTemplatesToStorage(list);
    handleSelectTemplate(newId);
    setNewTmplName('');
    setShowAddTmplForm(false);
    setWorkflowStep('template-design');
  };

  const closeAddTemplateDialog = () => {
    setShowAddTmplForm(false);
    setNewTmplName('');
    setNewTmplW(75);
    setNewTmplH(45);
  };

  // Export templates list or single active template as standard json
  const handleExportTemplate = (tmpl: LabelTemplate) => {
    const dataStr = JSON.stringify(normalizeTemplate(tmpl), null, 2);
    const dataUri = 'data:application/json;charset=utf-8,' + encodeURIComponent(dataStr);
    const exportFileDefaultName = `模板_${tmpl.name?.replace(/\s+/g, '_') || tmpl.id}.json`;

    const linkElement = document.createElement('a');
    linkElement.setAttribute('href', dataUri);
    linkElement.setAttribute('download', exportFileDefaultName);
    linkElement.click();
  };

  // Import custom template JSON uploader
  const handleImportTemplate = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = async (event) => {
      try {
        const parsed = JSON.parse(event.target?.result as string);
        if (parsed.width && parsed.height && Array.isArray(parsed.elements)) {
          const newId = `imported_${Date.now()}`;
          const newTmpl = normalizeTemplate({
            id: newId,
            name: parsed.name || `导入外部模板_${Date.now()}`,
            width: Number(parsed.width) || 70,
            height: Number(parsed.height) || 40,
            elements: parsed.elements,
            variableList: parsed.variableList,
            variableDefaults: parsed.variableDefaults,
            paper: parsed.paper,
            cutLine: parsed.cutLine,
            showPdfCutLines: parsed.showPdfCutLines,
          });
          const list = [...templates, newTmpl];
          saveTemplatesToStorage(list);
          handleSelectTemplate(newId);
          await showAlert('模板读取解析成功，已追加至库中。', { variant: 'success' });
        } else {
          await showAlert('JSON格式错误：外部模板必须至少包含 width, height, 以及 elements 分组', {
            variant: 'error',
          });
        }
      } catch (err) {
        await showAlert('文件解码失败，请确保您上传的是合法的 json 模板结构文件。', {
          variant: 'error',
        });
      }
    };
    reader.readAsText(file);
    e.target.value = ''; // clears input
  };

  // Delete customized template
  const handleDeleteTemplate = async (idToDelete: string) => {
    const confirmed = await showConfirm('您确定要彻底删除该标签模板吗？此步骤无法逆转。', {
      title: '删除模板',
      confirmLabel: '删除',
      variant: 'error',
    });
    if (!confirmed) return;

    const remaining = templates.filter((t) => t.id !== idToDelete);
    saveTemplatesToStorage(remaining);

    if (selectedTemplateId === idToDelete) {
      if (remaining.length > 0) {
        handleSelectTemplate(remaining[0].id!);
      } else {
        setSelectedTemplateId('');
        try {
          localStorage.removeItem('selected_label_template_id_v2');
        } catch (e) {}
        setWorkflowStep('template-select');
      }
    }
  };

  const dataColumns = importData?.columns ?? [];
  const activeRows = importData?.rows ?? [];

  const templateVariables = useMemo(
    () => extractTemplateVariables(workingTemplate),
    [workingTemplate]
  );

  const mappedRows = useMemo(
    () =>
      activeRows.map((row) =>
        applyRowVariableMapping(
          row,
          variableColumnMapping,
          templateVariables,
          workingTemplate.variableDefaults
        )
      ),
    [activeRows, variableColumnMapping, templateVariables, workingTemplate.variableDefaults]
  );

  const layoutResult = useMemo(
    () => buildPrintablePages(mappedRows, paper, workingTemplate, draftExportRange),
    [mappedRows, paper, workingTemplate, draftExportRange]
  );

  const {
    pages: printablePages,
    gridCols: gridInfoCols,
    gridRows: gridInfoRows,
    labelsPerPage,
    totalPages,
    selectedCount,
  } = layoutResult;

  const gridInfo = useMemo(
    () => ({ cols: gridInfoCols, rows: gridInfoRows }),
    [gridInfoCols, gridInfoRows]
  );

  const appliedMappedRows = useMemo(() => {
    if (!appliedExportData) return [];
    return appliedExportData.rows.map((row) =>
      applyRowVariableMapping(
        row,
        appliedExportData.mapping,
        templateVariables,
        workingTemplate.variableDefaults
      )
    );
  }, [appliedExportData, templateVariables, workingTemplate.variableDefaults]);

  const appliedExportRange = appliedExportData?.exportRange ?? DEFAULT_EXPORT_RANGE;

  const appliedLayoutResult = useMemo(
    () => buildPrintablePages(appliedMappedRows, paper, workingTemplate, appliedExportRange),
    [appliedMappedRows, paper, workingTemplate, appliedExportRange]
  );

  const dataStale = useMemo(() => {
    if (!importData) return appliedExportData !== null;
    if (!appliedExportData) return true;
    if (
      importData.fileName !== appliedExportData.fileName ||
      importData.currentSheet !== appliedExportData.currentSheet ||
      importData.rows !== appliedExportData.rows
    ) {
      return true;
    }
    const draftKeys = Object.keys(variableColumnMapping).sort();
    const appliedKeys = Object.keys(appliedExportData.mapping).sort();
    if (draftKeys.length !== appliedKeys.length) return true;
    if (draftKeys.some((key) => variableColumnMapping[key] !== appliedExportData.mapping[key])) {
      return true;
    }
    return !exportRangeEquals(draftExportRange, appliedExportData.exportRange);
  }, [importData, variableColumnMapping, appliedExportData, draftExportRange]);

  const handleApplyData = async () => {
    if (!importData || activeRows.length === 0) {
      await showAlert('请先上传 Excel 或 CSV 数据。', { variant: 'warning' });
      return;
    }
    if (selectedCount === 0) {
      await showAlert('当前数据范围内没有可预览的标签，请调整范围设置。', { variant: 'warning' });
      return;
    }
    const nextExportRange = { ...draftExportRange };
    setAppliedExportData({
      fileName: importData.fileName,
      currentSheet: importData.currentSheet,
      rows: importData.rows,
      mapping: { ...variableColumnMapping },
      exportRange: nextExportRange,
    });
    setPreviewSnapshot({
      pages: layoutResult.pages,
      gridCols: layoutResult.gridCols,
      labelsPerPage: layoutResult.labelsPerPage,
      totalPages: layoutResult.totalPages,
      selectedCount: layoutResult.selectedCount,
      paper,
      exportRange: nextExportRange,
    });
    setPreviewLayoutStale(false);
  };

  const handleRedrawPreview = async () => {
    if (!appliedExportData) {
      await showAlert('请先应用数据后再重新绘制预览。', { variant: 'warning' });
      return;
    }
    if (appliedLayoutResult.selectedCount === 0) {
      await showAlert('当前数据范围内没有可预览的标签，请调整范围设置。', { variant: 'warning' });
      return;
    }
    setPreviewSnapshot({
      pages: appliedLayoutResult.pages,
      gridCols: appliedLayoutResult.gridCols,
      labelsPerPage: appliedLayoutResult.labelsPerPage,
      totalPages: appliedLayoutResult.totalPages,
      selectedCount: appliedLayoutResult.selectedCount,
      paper,
      exportRange: appliedExportRange,
    });
    setPreviewLayoutStale(false);
  };

  useEffect(() => {
    if (previewSnapshot !== null && appliedExportData !== null) {
      setPreviewLayoutStale(true);
    }
  }, [workingTemplate.elements, workingTemplate.width, workingTemplate.height]);

  useEffect(() => {
    if (workflowStep !== 'print-view') return;
    if (!appliedExportData) return;

    const layout = buildPrintablePages(
      appliedMappedRows,
      paper,
      workingTemplate,
      appliedExportData.exportRange
    );

    setPreviewSnapshot({
      pages: layout.pages,
      gridCols: layout.gridCols,
      labelsPerPage: layout.labelsPerPage,
      totalPages: layout.totalPages,
      selectedCount: layout.selectedCount,
      paper,
      exportRange: appliedExportData.exportRange,
    });
    setPreviewLayoutStale(false);
  }, [
    paper,
    workflowStep,
    appliedExportData,
    appliedMappedRows,
    workingTemplate.width,
    workingTemplate.height,
  ]);

  const pdfExportImage = useMemo(() => {
    const hasCode = workingTemplate.elements.some(
      (e) => e.type === 'barcode' || e.type === 'qrcode'
    );
    return hasCode
      ? { imageFormat: 'png' as const, jsPdfFormat: 'PNG' as const, scale: 10 }
      : { imageFormat: 'jpeg' as const, jsPdfFormat: 'JPEG' as const, scale: 10 };
  }, [workingTemplate.elements]);

  const exportPdf = async () => {
    if (!activeTemplate) return;
    if (!appliedExportData) {
      await showAlert('请先应用数据后再导出 PDF。', { variant: 'warning' });
      return;
    }
    if (appliedLayoutResult.selectedCount === 0) {
      await showAlert('当前数据范围内没有可排版的标签，请调整范围设置。', { variant: 'warning' });
      return;
    }

    const labelTotal = appliedLayoutResult.selectedCount;
    const exportTotalPages = appliedLayoutResult.totalPages;

    setPdfGenerating(true);
    setPdfProgress({
      done: 0,
      total: labelTotal,
      page: 0,
      totalPages: exportTotalPages,
      phase: 'render',
    });

    const safeName = activeTemplate.name.replace(/[^\w\u4e00-\u9fa5-]+/g, '_').slice(0, 40) || 'labels';
    const progressLastUpdate = { current: 0 };

    try {
      await exportLabelsPdfAsync({
        paper,
        template: activeTemplate,
        printablePages: appliedLayoutResult.pages,
        gridCols: appliedLayoutResult.gridCols,
        cutLine,
        filename: `${safeName}_${exportTotalPages}页.pdf`,
        imageFormat: pdfExportImage.jsPdfFormat,
        renderLabel: (label) =>
          renderLabelToDataUrl({
            widthMm: activeTemplate.width,
            heightMm: activeTemplate.height,
            elements: activeTemplate.elements,
            rowData: label.row,
            rowIndex: label.sourceIndex,
            showBorder: false,
            mode: 'output',
            scale: pdfExportImage.scale,
            imageFormat: pdfExportImage.imageFormat,
            jpegQuality: 0.9,
          }),
        onProgress: (progress) => {
          const now = Date.now();
          const isDone = progress.done >= progress.total || progress.phase === 'save';
          if (isDone || now - progressLastUpdate.current >= 150) {
            progressLastUpdate.current = now;
            setPdfProgress(progress);
          }
        },
      });
    } catch (e) {
      console.error('PDF export failed', e);
      await showAlert('PDF 生成失败，请重试。', { variant: 'error' });
    } finally {
      setPdfGenerating(false);
    }
  };

  return (
    <div
      className={`min-h-screen flex flex-col font-sans ${
        workflowStep === 'template-design' || (workflowStep === 'print-view' && !isMobile)
          ? 'bg-[#323232] text-[#e8e8e8] h-screen overflow-hidden'
          : workflowStep === 'print-view' && isMobile
          ? 'bg-slate-100 text-slate-800 h-screen overflow-hidden'
          : 'bg-slate-50 text-slate-800'
      }`}
    >
      {/* 
        =========================================
        SCREEN HEADER
        =========================================
      */}
      {!(isMobile && workflowStep === 'print-view') && (
      <header
        className={`no-print bg-slate-950 border-b border-slate-900 shrink-0 shadow flex flex-wrap items-center justify-between gap-4 mobile-template-header ${
          workflowStep === 'template-design' || workflowStep === 'print-view' ? 'px-4 py-2' : 'px-4 py-3 md:px-6 md:py-4'
        }`}
      >
        {/* Title logo and slogan description */}
        <div className="flex items-center gap-3 min-w-0">
          <div className="p-2 md:p-2.5 bg-indigo-500/10 text-indigo-400 border border-indigo-500/20 rounded-xl shadow-inner shrink-0">
            <Wand2 className="w-5 h-5" />
          </div>
          <div className="min-w-0">
            <h1 className="text-sm font-bold tracking-wider flex items-center gap-2 text-slate-100 uppercase">
              <span className="truncate">{isMobile ? '批量标签排版印刷生成器' : '批量标签排版印刷生成器'}</span>
              <span className="text-[9.5px] bg-indigo-600 text-white font-extrabold px-1.5 py-0.5 rounded shadow-sm tracking-normal shrink-0">PDF</span>
            </h1>
            {workflowStep !== 'template-design' && workflowStep !== 'print-view' && !isMobile && (
              <p className="text-[11px] text-slate-400">
                数据所见即所得：可视化添加变量、绑定 Excel 多表、快速二元素对齐排料、高保真物理 A4 无损裁切
              </p>
            )}
          </div>
        </div>

        {workflowStep === 'template-select' && hasTemplates && !isMobile && (
          <div className="flex flex-wrap items-center gap-2 shrink-0">
            <button
              type="button"
              onClick={() => setShowAddTmplForm(true)}
              className="inline-flex items-center gap-1.5 px-4 py-2 bg-indigo-600 text-white rounded-xl text-xs font-semibold whitespace-nowrap transition hover:bg-indigo-700 shadow-sm cursor-pointer"
            >
              <Plus className="w-4 h-4 shrink-0" />
              新建模板
            </button>
            <label className="inline-flex items-center gap-1.5 px-4 py-2 bg-white/10 hover:bg-white/15 border border-slate-700 text-slate-100 rounded-xl text-xs font-semibold whitespace-nowrap transition shadow-sm cursor-pointer">
              <Upload className="w-4 h-4 shrink-0" />
              导入 JSON 模板
              <input
                type="file"
                accept=".json"
                onChange={handleImportTemplate}
                className="hidden"
              />
            </label>
          </div>
        )}
      </header>
      )}

      {/* Primary Workspace scroll container */}
      <main
        className={`no-print flex-1 flex flex-col w-full ${
          workflowStep === 'template-design' || workflowStep === 'print-view'
            ? 'overflow-hidden min-h-0'
            : 'overflow-auto p-4 md:p-6 max-w-[1720px] mx-auto gap-6'
        }`}
      >

        {/* ========================================================
            STEP 1: Template Selection, Import, and Excel binds dashboard
            ======================================================== */}
        {workflowStep === 'template-select' && (
          <div className="space-y-4 md:space-y-6">
            {hasTemplates ? (
              <div>
                <h2 className="text-base font-bold text-gray-900">标签模板库</h2>
                <p className="text-xs text-gray-400 mt-1">
                  {isMobile
                    ? '选择模板 → 上传 Excel → 关联变量 → 生成 PDF'
                    : '选择模板规格后进行设计与排版导出，或使用右上角按钮新建、导入模板。'}
                </p>
              </div>
            ) : (
              <div className="flex flex-col items-center justify-center text-center px-6 py-16 md:py-24">
                <div className="w-16 h-16 rounded-2xl bg-indigo-50 text-indigo-500 flex items-center justify-center mb-5 border border-indigo-100">
                  <Wand2 className="w-8 h-8" />
                </div>
                <h2 className="text-lg font-bold text-gray-900">还没有标签模板</h2>
                <p className="text-sm text-gray-500 mt-2 max-w-md leading-relaxed">
                  {isMobile
                    ? '请导入已有模板，或电脑端进行设计。'
                    : '创建模板开始可视化设计，或导入已有的 JSON 模板文件。'}
                </p>
                <div className="flex flex-col sm:flex-row items-center justify-center gap-3 mt-8">
                  {!isMobile && (
                    <button
                      type="button"
                      onClick={() => setShowAddTmplForm(true)}
                      className="inline-flex items-center justify-center gap-2 px-5 py-2.5 bg-indigo-600 hover:bg-indigo-700 text-white rounded-xl text-sm font-semibold transition shadow-sm cursor-pointer"
                    >
                      <Plus className="w-4 h-4 shrink-0" />
                      新建模板
                    </button>
                  )}
                  <label className="inline-flex items-center justify-center gap-2 px-5 py-2.5 bg-white border border-gray-200 hover:border-indigo-300 text-gray-700 rounded-xl text-sm font-semibold transition shadow-sm cursor-pointer shrink-0">
                    <Upload className="w-4 h-4 shrink-0" />
                    导入 JSON 模板
                    <input
                      type="file"
                      accept=".json"
                      onChange={handleImportTemplate}
                      className="hidden"
                    />
                  </label>
                </div>
              </div>
            )}

            {hasTemplates && (
            <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
              {templates.map((tmpl) => {
                const isActive = tmpl.id === selectedTemplateId;
                const { displayWidthPx, displayHeightPx } = fitTemplatePreviewSize(
                  tmpl.width,
                  tmpl.height
                );

                return (
                  <div
                    key={tmpl.id}
                    onClick={() => handleSelectTemplate(tmpl.id!)}
                    className={`bg-white border rounded-2xl p-5 shadow-xs transition-all flex flex-col cursor-pointer relative overflow-hidden group select-none ${
                      isActive
                        ? 'ring-2 ring-indigo-500 border-indigo-500 bg-indigo-50/5'
                        : 'border-gray-200 hover:shadow-md hover:border-indigo-200'
                    }`}
                  >
                    {isActive && (
                      <div
                        className="absolute top-0 right-0 py-1.5 px-3 text-[10px] font-bold rounded-bl-xl text-white"
                        style={{ backgroundColor: '#6366f1' }}
                      >
                        当前选中
                      </div>
                    )}

                    <div className="space-y-1 pr-12 mb-3">
                      <span className="text-[10px] font-mono font-extrabold text-indigo-700 bg-indigo-50 px-2 py-0.5 rounded-lg border border-indigo-100">
                        {tmpl.width} × {tmpl.height} mm
                      </span>
                      <h3 className="text-sm font-bold text-gray-900 mt-1 leading-snug">{tmpl.name}</h3>
                      <p className="text-[10px] text-gray-400">{tmpl.elements.length} 个元素</p>
                    </div>

                    {/* Preview */}
                    <div
                      className="rounded-xl bg-gray-50 p-3 overflow-hidden flex items-center justify-center"
                      style={{
                        minHeight: `${TEMPLATE_PREVIEW_MAX_H + 24}px`,
                      }}
                    >
                      <div
                        className="bg-white shadow-sm shrink-0 overflow-hidden"
                        style={{
                          width: `${displayWidthPx}px`,
                          height: `${displayHeightPx}px`,
                        }}
                      >
                        <CanvasLabelImage
                          widthMm={tmpl.width}
                          heightMm={tmpl.height}
                          elements={tmpl.elements}
                          rowData={null}
                          rowIndex={0}
                          showBorder={true}
                          variableDefaults={tmpl.variableDefaults ?? null}
                        />
                      </div>
                    </div>

                    {/* Actions */}
                    <div className={`flex flex-wrap items-center gap-2 mt-4 text-xs ${isMobile ? 'mobile-template-actions' : ''}`}>
                      {!isMobile && (
                        <button
                          onClick={(e) => {
                            e.stopPropagation();
                            handleSelectTemplate(tmpl.id!);
                            setWorkflowStep('template-design');
                          }}
                          className="shrink-0 whitespace-nowrap inline-flex items-center gap-1 px-3 py-1.5 bg-gray-50 text-indigo-700 border border-gray-100 hover:border-indigo-300 hover:bg-indigo-50 rounded-lg text-[11px] font-bold transition-colors cursor-pointer"
                        >
                          <Code className="w-3.5 h-3.5 shrink-0" />
                          设计
                        </button>
                      )}
                      <button
                        onClick={(e) => {
                          e.stopPropagation();
                          openPrintView(tmpl.id!);
                        }}
                        className={`shrink-0 whitespace-nowrap inline-flex items-center gap-1 px-3 py-1.5 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg text-[11px] font-bold transition shadow-xs cursor-pointer ${
                          isMobile ? 'mobile-primary-btn flex-1' : ''
                        }`}
                      >
                        <FileDown className="w-3.5 h-3.5 shrink-0" />
                        {isMobile ? '上传数据并导出 PDF' : '排版导出'}
                      </button>
                      {!isMobile && (
                        <>
                          <button
                            onClick={(e) => {
                              e.stopPropagation();
                              handleExportTemplate(tmpl);
                            }}
                            className="shrink-0 p-1.5 bg-gray-50 text-gray-500 hover:bg-gray-100 border border-gray-100 hover:border-gray-300 rounded-lg inline-flex items-center justify-center transition cursor-pointer"
                            title="导出 JSON"
                          >
                            <Download className="w-3.5 h-3.5" />
                          </button>
                          <button
                            onClick={(e) => {
                              e.stopPropagation();
                              handleDeleteTemplate(tmpl.id!);
                            }}
                            className="shrink-0 p-1.5 bg-gray-50 text-rose-500 hover:text-white hover:bg-rose-600 border border-gray-100 rounded-lg inline-flex items-center justify-center transition cursor-pointer"
                            title="删除模板"
                          >
                            <Trash2 className="w-3.5 h-3.5" />
                          </button>
                        </>
                      )}
                    </div>
                  </div>
                );
              })}
            </div>
            )}
          </div>
        )}

        {/* ========================================================
            STEP 2: The visual drag-and-drop label designer
            ======================================================== */}
        {workflowStep === 'template-design' && isMobile && hasTemplates && (
          <div className="mobile-design-block bg-[#292929] text-[#e8e8e8] flex-1">
            <p className="text-sm text-[#ccc] max-w-[280px] leading-relaxed">
              可视化模板设计需要在电脑端操作。移动端可直接上传数据并生成 PDF。
            </p>
            <button
              type="button"
              onClick={() => openPrintView()}
              className="inline-flex items-center gap-2 px-5 py-2.5 bg-[#31a8ff] text-white text-sm font-semibold rounded-lg cursor-pointer"
            >
              <FileDown className="w-4 h-4" />
              去上传数据
            </button>
            <button
              type="button"
              onClick={() => setWorkflowStep('template-select')}
              className="text-[12px] text-[#999] underline cursor-pointer"
            >
              返回模板列表
            </button>
          </div>
        )}

        {workflowStep === 'template-design' && !isMobile && hasTemplates && activeTemplate && (
          <div className="flex-1 flex flex-col min-h-0">
            {/* Options bar — Photoshop style */}
            <div className="ps-options-bar">
              <button
                onClick={() => setWorkflowStep('template-select')}
                className="text-[#aaa] hover:text-white transition cursor-pointer"
              >
                ← 返回
              </button>
              <span className="text-[#666]">|</span>
              <span className="font-medium text-[#e8e8e8] truncate max-w-[200px]">
                {activeTemplate.name}
              </span>
              <span className="text-[#666] text-[10px]">
                {activeTemplate.width} × {activeTemplate.height} mm
              </span>
              <div className="flex-1" />
              <span className="hidden md:inline text-[10px] text-[#666]">
                Shift/Ctrl+点击多选 · V 移动 · T 文本 · 图片工具栏
              </span>
              <button
                onClick={() => openPrintView()}
                className="inline-flex items-center gap-1 px-3 py-1 bg-[#31a8ff] hover:bg-[#2890d8] text-white text-[11px] font-semibold transition cursor-pointer"
              >
                <FileDown className="w-3 h-3" />
                排版导出
              </button>
            </div>

            {/* Workspace: toolbar + canvas + panels */}
            <div className="flex-1 flex min-h-0">
              <LabelDesigner
                template={activeTemplate}
                onChange={handleTemplateChange}
                selectedElementIds={selectedElementIds}
                onSelectElements={setSelectedElementIds}
              />
              <PropSidebar
                template={activeTemplate}
                onChangeTemplate={handleTemplateChange}
                selectedElementIds={selectedElementIds}
                onSelectElements={setSelectedElementIds}
                activeTab="element"
                onChangeTab={() => {}}
                paper={paper}
              />
            </div>
          </div>
        )}

        {/* ========================================================
            STEP 3: Pagination layouts & Printed grids configuration
            ======================================================== */}
        {workflowStep === 'print-view' && isMobile && hasTemplates && activeTemplate && (
          <MobileExportView
            template={activeTemplate}
            templateName={activeTemplate.name ?? '标签'}
            templateVariables={templateVariables}
            importData={importData}
            onDataLoaded={handleDataLoaded}
            onClear={handleClearData}
            dataColumns={dataColumns}
            variableColumnMapping={variableColumnMapping}
            onChangeMapping={handleMappingChange}
            paper={paper}
            onChangePaper={handlePaperChange}
            rows={mappedRows}
            draftExportRange={draftExportRange}
            onChangeDraftExportRange={setDraftExportRange}
            cutLine={cutLine}
            onChangeCutLine={handleCutLineChange}
            dataStale={dataStale}
            dataApplied={appliedExportData !== null}
            onApplyData={handleApplyData}
            appliedSelectedCount={appliedLayoutResult.selectedCount}
            appliedTotalPages={appliedLayoutResult.totalPages}
            appliedGridCols={appliedLayoutResult.gridCols}
            appliedGridRows={appliedLayoutResult.gridRows}
            draftSelectedCount={selectedCount}
            pdfGenerating={pdfGenerating}
            onBack={() => setWorkflowStep('template-select')}
            onExportPdf={exportPdf}
          />
        )}

        {workflowStep === 'print-view' && !isMobile && hasTemplates && activeTemplate && (
          <div className="flex-1 flex flex-col min-h-0 print-view-shell">
            <div className="ps-options-bar">
              <button
                type="button"
                onClick={() => setWorkflowStep('template-select')}
                className="text-[#aaa] hover:text-white transition cursor-pointer"
              >
                ← 返回
              </button>
              <span className="text-[#666]">|</span>
              <span className="font-medium text-[#e8e8e8] truncate max-w-[180px]">
                {activeTemplate.name}
              </span>
              <span className="text-[#666] text-[10px]">
                {gridInfo.cols}×{gridInfo.rows} · {totalPages} 页 ·{' '}
                {selectedCount < activeRows.length
                  ? `${selectedCount}/${activeRows.length} 行`
                  : `${activeRows.length} 行`}
              </span>
              <div className="flex-1" />
              <button
                type="button"
                onClick={() => setWorkflowStep('template-design')}
                className="inline-flex items-center gap-1 px-2.5 py-1 border border-[#555] hover:border-[#777] text-[#ccc] hover:text-white text-[10px] transition cursor-pointer"
              >
                修改模板
              </button>
              <button
                type="button"
                onClick={exportPdf}
                disabled={
                  !appliedExportData || appliedLayoutResult.selectedCount === 0 || pdfGenerating
                }
                className={`inline-flex items-center gap-1.5 px-3 py-1 text-[11px] font-semibold transition cursor-pointer ${
                  appliedExportData && appliedLayoutResult.selectedCount > 0 && !pdfGenerating
                    ? 'bg-[#31a8ff] hover:bg-[#2890d8] text-white'
                    : 'bg-[#444] text-[#666] cursor-not-allowed'
                }`}
              >
                {pdfGenerating ? (
                  <Loader2 className="w-3 h-3 shrink-0 animate-spin" />
                ) : (
                  <FileDown className="w-3 h-3 shrink-0" />
                )}
                {pdfGenerating ? '生成中…' : '生成并保存 PDF'}
              </button>
            </div>

            <div className="flex-1 flex min-h-0 print-view-body overflow-hidden">
              <LayoutPreview
                paper={previewSnapshot !== null ? previewSnapshot.paper : paper}
                template={activeTemplate}
                printablePages={previewSnapshot?.pages ?? []}
                gridCols={previewSnapshot?.gridCols ?? gridInfo.cols}
                labelsPerPage={previewSnapshot?.labelsPerPage ?? labelsPerPage}
                totalPages={previewSnapshot?.totalPages ?? totalPages}
                selectedCount={previewSnapshot?.selectedCount ?? selectedCount}
                totalRowCount={activeRows.length}
                draftTotalPages={totalPages}
                draftSelectedCount={selectedCount}
                previewReady={previewSnapshot !== null}
                previewLayoutStale={previewLayoutStale}
                cutLine={cutLine}
                activeRowIndex={activeRowIndex}
                onSelectRowIndex={setActiveRowIndex}
              />
              <ExportSidebar
                importData={importData}
                onDataLoaded={handleDataLoaded}
                onClear={handleClearData}
                templateName={activeTemplate.name ?? '标签'}
                templateVariables={templateVariables}
                dataColumns={dataColumns}
                variableColumnMapping={variableColumnMapping}
                onChangeMapping={handleMappingChange}
                paper={paper}
                onChangePaper={handlePaperChange}
                template={activeTemplate}
                rows={mappedRows}
                draftExportRange={draftExportRange}
                onChangeDraftExportRange={setDraftExportRange}
                cutLine={cutLine}
                onChangeCutLine={handleCutLineChange}
                previewReady={previewSnapshot !== null}
                dataStale={dataStale}
                previewLayoutStale={previewLayoutStale}
                dataApplied={appliedExportData !== null}
                onApplyData={handleApplyData}
                onRedrawPreview={handleRedrawPreview}
                draftSelectedCount={selectedCount}
              />
            </div>
          </div>
        )}
      </main>

      {showAddTmplForm && (
        <div
          className="fixed inset-0 z-[9000] flex items-center justify-center bg-slate-950/60 backdrop-blur-sm p-4"
          onClick={closeAddTemplateDialog}
          role="presentation"
        >
          <div
            className="bg-white rounded-2xl shadow-2xl w-full max-w-lg overflow-hidden"
            onClick={(e) => e.stopPropagation()}
            role="dialog"
            aria-modal="true"
            aria-labelledby="add-template-dialog-title"
          >
            <div className="flex items-center justify-between px-6 py-4 border-b border-gray-100">
              <h3
                id="add-template-dialog-title"
                className="text-sm font-bold text-gray-900"
              >
                新建模板
              </h3>
              <button
                type="button"
                onClick={closeAddTemplateDialog}
                className="p-1.5 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-lg transition cursor-pointer"
                aria-label="关闭"
              >
                <X className="w-4 h-4" />
              </button>
            </div>
            <form onSubmit={handleAddTemplateSubmit} className="px-6 py-5 space-y-4">
              <div>
                <label className="block text-[11px] font-semibold text-gray-500 mb-1.5">
                  模板名称
                </label>
                <input
                  type="text"
                  required
                  autoFocus
                  placeholder="如: 电商仓外贴标 70x40"
                  value={newTmplName}
                  onChange={(e) => setNewTmplName(e.target.value)}
                  className="w-full px-3 py-2 bg-gray-50 border border-gray-200 rounded-lg text-sm focus:border-indigo-400 focus:outline-none"
                />
              </div>
              <div className="grid grid-cols-2 gap-4">
                <div>
                  <label className="block text-[11px] font-semibold text-gray-500 mb-1.5">
                    标签宽度 (mm)
                  </label>
                  <input
                    type="number"
                    required
                    min="10"
                    max="150"
                    value={newTmplW}
                    onChange={(e) => setNewTmplW(Number(e.target.value))}
                    className="w-full px-3 py-2 bg-gray-50 border border-gray-200 rounded-lg text-sm font-mono focus:border-indigo-400 focus:outline-none"
                  />
                </div>
                <div>
                  <label className="block text-[11px] font-semibold text-gray-500 mb-1.5">
                    标签高度 (mm)
                  </label>
                  <input
                    type="number"
                    required
                    min="10"
                    max="150"
                    value={newTmplH}
                    onChange={(e) => setNewTmplH(Number(e.target.value))}
                    className="w-full px-3 py-2 bg-gray-50 border border-gray-200 rounded-lg text-sm font-mono focus:border-indigo-400 focus:outline-none"
                  />
                </div>
              </div>
              <div className="flex justify-end gap-2 pt-2">
                <button
                  type="button"
                  onClick={closeAddTemplateDialog}
                  className="px-4 py-2 border border-gray-200 text-gray-600 hover:bg-gray-50 rounded-lg text-sm font-medium cursor-pointer"
                >
                  取消
                </button>
                <button
                  type="submit"
                  className="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 text-sm font-semibold cursor-pointer"
                >
                  创建并进入设计
                </button>
              </div>
            </form>
          </div>
        </div>
      )}

      {pdfGenerating && (
        <div className="fixed inset-0 z-[9999] flex items-center justify-center bg-slate-950/70 backdrop-blur-sm">
          <div className="bg-white rounded-2xl shadow-2xl px-8 py-6 flex flex-col items-center gap-4 min-w-[280px]">
            <Loader2 className="w-10 h-10 text-indigo-600 animate-spin" />
            <div className="text-center">
              <p className="text-sm font-bold text-gray-900">
                {pdfProgress.phase === 'save' ? '正在保存 PDF 文件…' : '正在生成 PDF'}
              </p>
              <p className="text-xs text-gray-500 mt-1">
                {pdfProgress.phase === 'save'
                  ? '即将完成，请稍候'
                  : `第 ${pdfProgress.page} / ${pdfProgress.totalPages} 页 · ${pdfProgress.done} / ${pdfProgress.total} 张标签`}
              </p>
            </div>
            <div className="w-full h-1.5 bg-gray-100 rounded-full overflow-hidden">
              <div
                className="h-full bg-indigo-600 transition-all duration-200"
                style={{
                  width: pdfProgress.total
                    ? `${(pdfProgress.done / pdfProgress.total) * 100}%`
                    : '0%',
                }}
              />
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
