import { useCallback, useEffect, useState, type ReactNode } from 'react';
import { useNavigate } from 'react-router-dom';
import dayjs from 'dayjs';
import {
  Button,
  Card,
  DatePicker,
  Form,
  Input,
  InputNumber,
  Modal,
  Popconfirm,
  Popover,
  Select,
  Space,
  Spin,
  Table,
  Tag,
  Tooltip,
  Typography,
  message,
} from 'antd';
import {
  DeleteOutlined,
  EyeOutlined,
  FolderOpenOutlined,
  PrinterOutlined,
  QrcodeOutlined,
  ReloadOutlined,
  ScanOutlined,
  SearchOutlined,
  TeamOutlined,
  UserOutlined,
} from '@ant-design/icons';
import type { ColumnsType } from 'antd/es/table';
import { inboxApi, type InboxBarcode, type InboxFile } from '../api/inbox';
import { barcodeTemplatesApi, type BarcodeTemplate } from '../api/barcode-templates';
import { labelPrintAgentApi } from '../api/labelPrintAgent';
import { userSettingsApi } from '../api/userSettings';
import { useIsMobile } from '../hooks/useIsMobile';
import MobileCardList from '../components/MobileCardList';

const { Title } = Typography;

function formatDate(iso: string): string {
  const d = new Date(iso);
  return d.toLocaleString('de-DE', {
    day: '2-digit',
    month: '2-digit',
    year: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
  });
}

function renderSourceTag(src: InboxFile['source']): ReactNode {
  return src === 'user' ? (
    <Tag icon={<UserOutlined />} color="purple">
      Persönlich
    </Tag>
  ) : (
    <Tag icon={<FolderOpenOutlined />} color="blue">
      Gemeinsam
    </Tag>
  );
}

function renderBarcodes(barcodes: InboxBarcode[]): ReactNode {
  if (!barcodes || barcodes.length === 0) {
    return <Typography.Text type="secondary">—</Typography.Text>;
  }
  return (
    <Space size={[4, 4]} wrap>
      {barcodes.map((b, idx) => {
        const label = b.templateName ?? b.value;
        const color = b.templateName ? 'green' : 'default';
        return (
          <Tooltip
            key={`${b.page}-${idx}`}
            title={
              <div>
                <div>Seite {b.page}</div>
                <div style={{ fontFamily: 'monospace' }}>{b.value}</div>
                {!b.templateName && <div>Keine passende Vorlage</div>}
              </div>
            }
          >
            <Tag icon={<QrcodeOutlined />} color={color}>
              S.{b.page}: {label}
            </Tag>
          </Tooltip>
        );
      })}
    </Space>
  );
}

function DocumentPreviewPopover({ record, children }: { record: InboxFile; children: ReactNode }) {
  const [blobUrl, setBlobUrl] = useState<string | null>(null);
  const [loading, setLoading] = useState(false);

  const handleOpenChange = async (open: boolean) => {
    if (open && !blobUrl && !loading) {
      setLoading(true);
      try {
        const blob = await inboxApi.thumbnailBlob(record.id, 1);
        setBlobUrl(URL.createObjectURL(blob));
      } catch {
        // error handling handled implicitly
      } finally {
        setLoading(false);
      }
    }
  };

  useEffect(() => {
    return () => {
      if (blobUrl) {
        URL.revokeObjectURL(blobUrl);
      }
    };
  }, [blobUrl]);

  const content = (
    <div style={{ width: 250, minHeight: 150, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
      {loading ? (
        <Spin />
      ) : blobUrl ? (
        <img src={blobUrl} alt="Vorschau" style={{ maxWidth: '100%', maxHeight: 350, objectFit: 'contain' }} />
      ) : (
        <Typography.Text type="secondary">Vorschau nicht verfügbar</Typography.Text>
      )}
    </div>
  );

  return (
    <Popover content={content} title="Vorschau (Seite 1)" onOpenChange={handleOpenChange} placement="right" mouseEnterDelay={0.5}>
      <span style={{ cursor: 'pointer', textDecoration: 'underline dashed #ccc', display: 'inline-block' }}>{children}</span>
    </Popover>
  );
}

function buildInitialFieldValues(template: BarcodeTemplate | null): Record<string, string> {
  const today = dayjs().format('YYYY-MM-DD');
  const values: Record<string, string> = {};
  for (const field of template?.LabelInputFields ?? []) {
    if (field.type === 'date') values[field.name] = today;
  }
  return values;
}

export default function InboxPage() {
  const navigate = useNavigate();
  const isMobile = useIsMobile();
  const [files, setFiles] = useState<InboxFile[]>([]);
  const [loading, setLoading] = useState(true);
  const [search, setSearch] = useState('');
  const [rescanning, setRescanning] = useState(false);

  const [printDialogOpen, setPrintDialogOpen] = useState(false);
  const [labelTemplates, setLabelTemplates] = useState<BarcodeTemplate[]>([]);
  const [selectedTemplate, setSelectedTemplate] = useState<BarcodeTemplate | null>(null);
  const [fieldValues, setFieldValues] = useState<Record<string, string>>({});
  const [printing, setPrinting] = useState(false);
  const [labelCount, setLabelCount] = useState(1);

  const openPrintDialog = async () => {
    try {
      const [all, settings] = await Promise.all([
        barcodeTemplatesApi.list(),
        userSettingsApi.get(),
      ]);
      const enabled = all.filter((t) => t.LabelEnabled);
      setLabelTemplates(enabled);
      const defaultId = settings.defaultLabelTemplateId;
      const defaultTemplate = defaultId != null
        ? (enabled.find((t) => t.Id === defaultId) ?? null)
        : null;
      setSelectedTemplate(defaultTemplate);
      setFieldValues(buildInitialFieldValues(defaultTemplate));
    } catch {
      message.error('Vorlagen konnten nicht geladen werden');
      return;
    }
    setLabelCount(1);
    setPrintDialogOpen(true);
  };

  const handleTemplateSelect = (id: number) => {
    const t = labelTemplates.find((t) => t.Id === id) ?? null;
    setSelectedTemplate(t);
    setFieldValues(buildInitialFieldValues(t));
  };

  const handlePrint = async () => {
    if (!selectedTemplate) return;
    setPrinting(true);
    try {
      for (let i = 0; i < labelCount; i++) {
        await labelPrintAgentApi.createJob(selectedTemplate.Id, fieldValues);
      }
      message.success(labelCount === 1 ? 'Druckauftrag erstellt' : `${labelCount} Druckaufträge erstellt`);
      setPrintDialogOpen(false);
    } catch (err: any) {
      message.error(err?.response?.data?.message ?? 'Druckauftrag fehlgeschlagen');
    } finally {
      setPrinting(false);
    }
  };

  const load = useCallback(async () => {
    setLoading(true);
    try {
      const data = await inboxApi.list();
      setFiles(data);
    } catch {
      message.error('Dateien konnten nicht geladen werden');
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    load();
  }, [load]);

  useEffect(() => {
    const id = setInterval(load, 30_000);
    return () => clearInterval(id);
  }, [load]);

  const handleRescan = async () => {
    setRescanning(true);
    const hide = message.loading('Rescan läuft – das kann je nach Anzahl der Dokumente dauern …', 0);
    try {
      const { scanned, failed } = await inboxApi.rescan();
      hide();
      if (failed > 0) {
        message.warning(`Rescan abgeschlossen: ${scanned} ok, ${failed} fehlgeschlagen`);
      } else {
        message.success(`Rescan abgeschlossen: ${scanned} Dokument(e) neu gescannt`);
      }
      await load();
    } catch {
      hide();
      message.error('Rescan fehlgeschlagen');
    } finally {
      setRescanning(false);
    }
  };

  const handleDelete = async (id: string) => {
    try {
      await inboxApi.remove(id);
      message.success('Dokument gelöscht');
      await load();
    } catch {
      message.error('Löschen fehlgeschlagen');
    }
  };

  const handleUpdateSource = async (id: string, current: InboxFile['source']) => {
    const next = current === 'all' ? 'user' : 'all';
    try {
      await inboxApi.updateSource(id, next);
      message.success(
        next === 'all' ? 'Zu Öffentlich verschoben' : 'Zu Persönlich verschoben',
      );
      await load();
    } catch {
      message.error('Verschieben fehlgeschlagen');
    }
  };

  const filtered = files.filter((f) =>
    search ? f.name.toLowerCase().includes(search.toLowerCase()) : true,
  );

  // Karten-Ansicht sortiert wie die Tabelle (neueste zuerst)
  const sortedForMobile = [...filtered].sort((a, b) => b.createdAt.localeCompare(a.createdAt));

  const renderActions = (record: InboxFile, direction: 'column' | 'row' = 'column') => (
    <div style={{ display: 'flex', flexDirection: direction, alignItems: 'flex-start', flexWrap: 'wrap' }}>
      <Tooltip title="Vorschau öffnen">
        <Button
          type="link"
          icon={<EyeOutlined />}
          onClick={() => navigate(`/inbox/${encodeURIComponent(record.id)}`)}
        >
          Weiterverarbeiten
        </Button>
      </Tooltip>
      <Popconfirm
        title="Dokument löschen?"
        description="Datei und Datenbank-Eintrag werden dauerhaft entfernt."
        okText="Löschen"
        cancelText="Abbrechen"
        okButtonProps={{ danger: true }}
        onConfirm={() => handleDelete(record.id)}
      >
        <Button type="link" danger icon={<DeleteOutlined />}>
          Löschen
        </Button>
      </Popconfirm>
      <Tooltip
        title={
          record.source === 'all'
            ? 'In meinen persönlichen Scan-Ordner verschieben'
            : 'In den gemeinsamen Ordner (Öffentlich) verschieben'
        }
      >
        <Button
          type="link"
          icon={record.source === 'all' ? <UserOutlined /> : <TeamOutlined />}
          onClick={() => handleUpdateSource(record.id, record.source)}
        >
          {record.source === 'all' ? 'Zu Persönlich' : 'Zu Öffentlich'}
        </Button>
      </Tooltip>
    </div>
  );

  const columns: ColumnsType<InboxFile> = [
    {
      title: 'Dateiname',
      dataIndex: 'name',
      key: 'name',
      sorter: (a, b) => a.name.localeCompare(b.name),
      render: (name: string, record) => (
        <DocumentPreviewPopover record={record}>
          <Typography.Text>{name}</Typography.Text>
        </DocumentPreviewPopover>
      ),
    },
    {
      title: 'Quelle',
      dataIndex: 'source',
      key: 'source',
      width: 160,
      filters: [
        { text: 'Gemeinsam', value: 'all' },
        { text: 'Persönlich', value: 'user' },
      ],
      onFilter: (value, record) => record.source === value,
      render: (src: InboxFile['source']) => renderSourceTag(src),
    },
    {
      title: 'QR-Code / Vorlage',
      key: 'barcodes',
      width: 260,
      render: (_, record) => renderBarcodes(record.barcodes),
    },
    {
      title: 'Seiten',
      dataIndex: 'pageCount',
      key: 'pageCount',
      width: 100,
      sorter: (a, b) => a.pageCount - b.pageCount,
      render: (n: number) => (n > 0 ? n : <Typography.Text type="secondary">—</Typography.Text>),
    },
    {
      title: 'Empfangen',
      dataIndex: 'createdAt',
      key: 'createdAt',
      width: 180,
      defaultSortOrder: 'descend',
      sorter: (a, b) => a.createdAt.localeCompare(b.createdAt),
      render: (iso: string) => formatDate(iso),
    },
    {
      title: 'Aktionen',
      key: 'actions',
      width: 140,
      render: (_, record) => renderActions(record),
    },
  ];

  return (
    <div>
      <div
        style={{
          display: 'flex',
          justifyContent: 'space-between',
          alignItems: 'center',
          flexWrap: 'wrap',
          gap: 12,
          marginBottom: 16,
        }}
      >
        <div>
          <Title level={3} style={{ margin: 0 }}>
            Eingangsbox
          </Title>
          <Typography.Text type="secondary">
            Dateien aus <code>/mnt/scans/all</code> und Ihrem persönlichen
            Scan-Ordner.
          </Typography.Text>
        </div>
        <Space wrap>
          <Input
            prefix={<SearchOutlined />}
            placeholder="Suchen …"
            style={{ width: isMobile ? '100%' : 260 }}
            value={search}
            onChange={(e) => setSearch(e.target.value)}
            allowClear
          />
          <Button icon={<ReloadOutlined />} onClick={load} loading={loading}>
            Aktualisieren
          </Button>
          <Popconfirm
            title="Alle Dokumente neu scannen?"
            description="Alle PDFs in der Eingangsbox werden erneut auf QR-Codes geprüft. Das kann je nach Anzahl der Dokumente einige Zeit dauern."
            okText="Rescan starten"
            cancelText="Abbrechen"
            onConfirm={handleRescan}
          >
            <Button icon={<ScanOutlined />} loading={rescanning}>
              Rescan
            </Button>
          </Popconfirm>
          <Button icon={<PrinterOutlined />} onClick={openPrintDialog}>
            Etikett drucken
          </Button>
        </Space>
      </div>

      <Modal
        title="Etikett drucken"
        open={printDialogOpen}
        onCancel={() => setPrintDialogOpen(false)}
        onOk={handlePrint}
        okText="Drucken"
        cancelText="Abbrechen"
        confirmLoading={printing}
        okButtonProps={{ disabled: !selectedTemplate }}
      >
        <Form layout="vertical">
          <Form.Item label="Eingangsdokumentart">
            <Select
              placeholder="Vorlage wählen…"
              options={labelTemplates.map((t) => ({ value: t.Id, label: t.Name }))}
              onChange={handleTemplateSelect}
              value={selectedTemplate?.Id}
              style={{ width: '100%' }}
            />
          </Form.Item>

          <Form.Item label="Anzahl Etiketten">
            <InputNumber
              min={1}
              max={100}
              value={labelCount}
              onChange={(v) => setLabelCount(v ?? 1)}
              style={{ width: '100%' }}
            />
          </Form.Item>

          {selectedTemplate?.LabelInputFields?.map((field) => (
            <Form.Item key={field.name} label={field.label || field.name}>
              {field.type === 'date' ? (
                <DatePicker
                  style={{ width: '100%' }}
                  format="DD.MM.YYYY"
                  value={fieldValues[field.name] ? dayjs(fieldValues[field.name]) : null}
                  onChange={(d) =>
                    setFieldValues((prev) => ({
                      ...prev,
                      [field.name]: d ? d.format('YYYY-MM-DD') : '',
                    }))
                  }
                />
              ) : field.type === 'number' ? (
                <InputNumber
                  style={{ width: '100%' }}
                  value={fieldValues[field.name] ? Number(fieldValues[field.name]) : undefined}
                  onChange={(v) =>
                    setFieldValues((prev) => ({ ...prev, [field.name]: String(v ?? '') }))
                  }
                />
              ) : (
                <Input
                  value={fieldValues[field.name] ?? ''}
                  onChange={(e) =>
                    setFieldValues((prev) => ({ ...prev, [field.name]: e.target.value }))
                  }
                />
              )}
            </Form.Item>
          ))}
        </Form>
      </Modal>

      {isMobile ? (
        <MobileCardList<InboxFile>
          dataSource={sortedForMobile}
          rowKey="id"
          loading={loading}
          pagination={{
            pageSize: 25,
            showTotal: (t) => `${t} Dateien`,
          }}
          emptyText="Keine Dateien vorhanden"
          renderCard={(record) => (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
              <DocumentPreviewPopover record={record}>
                <Typography.Text strong>{record.name}</Typography.Text>
              </DocumentPreviewPopover>
              <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center' }}>
                {renderSourceTag(record.source)}
                <Typography.Text type="secondary" style={{ fontSize: 13 }}>
                  {record.pageCount > 0 ? `${record.pageCount} Seiten` : '—'} · {formatDate(record.createdAt)}
                </Typography.Text>
              </div>
              {renderBarcodes(record.barcodes)}
              {renderActions(record, 'row')}
            </div>
          )}
        />
      ) : (
        <Card>
          <Table<InboxFile>
            rowKey="id"
            columns={columns}
            dataSource={filtered}
            loading={loading}
            pagination={{
              pageSize: 25,
              showSizeChanger: true,
              showTotal: (t) => `${t} Dateien`,
            }}
            locale={{ emptyText: 'Keine Dateien vorhanden' }}
          />
        </Card>
      )}
    </div>
  );
}
