import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { Button, Dropdown, Empty, Form, Input, Modal, Popconfirm, Space, Spin, Steps, Tag, Tooltip, Typography, message } from 'antd';
import type { MenuProps } from 'antd';
import {
  ArrowLeftOutlined,
  DeleteOutlined,
  DownOutlined,
  FolderOpenOutlined,
  LeftOutlined,
  LoadingOutlined,
  MailOutlined,
  QrcodeOutlined,
  RedoOutlined,
  RightOutlined,
  SaveOutlined,
  ScissorOutlined,
  ThunderboltOutlined,
  UndoOutlined,
  UserOutlined,
  ZoomInOutlined,
  ZoomOutOutlined,
} from '@ant-design/icons';
import { useEditor, EditorContent } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
import Underline from '@tiptap/extension-underline';
import { inboxApi, type InboxBarcode, type InboxFile, type PostprocessActionResult } from '../api/inbox';
import { paperlessApi } from '../api/paperless';

const ZOOM_MIN = 0.5;
const ZOOM_MAX = 3;
const ZOOM_STEP = 0.25;

const { Title } = Typography;

interface DocumentSegment {
  index: number;
  pages: number[];
  belegname: string | null;
}

function buildDocuments(
  pageCount: number,
  splitPages: number[],
  deletedPages: number[],
  manualSplitPages: number[],
  barcodes: InboxBarcode[],
): DocumentSegment[] {
  if (pageCount === 0) return [];
  const deleted = new Set(deletedPages);
  const splits = new Set([...splitPages, ...manualSplitPages].filter((p) => !deleted.has(p)));

  const docs: DocumentSegment[] = [];
  let current: number[] = [];
  for (let n = 1; n <= pageCount; n++) {
    if (deleted.has(n)) continue;
    if (splits.has(n) && current.length > 0) {
      docs.push({ index: docs.length, pages: current, belegname: null });
      current = [];
    }
    current.push(n);
  }
  if (current.length > 0) {
    docs.push({ index: docs.length, pages: current, belegname: null });
  }

  // Belegname pro Segment: DateinameTemplate des zugehörigen Barcodes,
  // Fallback auf templateName falls DateinameTemplate nicht konfiguriert.
  const sortedBarcodes = [...barcodes].sort((a, b) => a.page - b.page);
  return docs.map((seg) => {
    const pageSet = new Set(seg.pages);
    const barcode = sortedBarcodes.find((b) => pageSet.has(b.page));
    const belegname = barcode?.dateinameTemplate || barcode?.templateName || null;
    return { ...seg, belegname };
  });
}

function thumbImageStyle(rotation: number, shortSidePx: number): React.CSSProperties {
  const isQuarter = rotation === 90 || rotation === 270;
  return {
    maxWidth: isQuarter ? shortSidePx : '100%',
    maxHeight: isQuarter ? shortSidePx : '100%',
    transform: `rotate(${rotation}deg)`,
    transition: 'transform 0.15s ease-out',
  };
}

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

interface CompareModalProps {
  open: boolean;
  paperlessDocumentId: number | null;
  inboxDocumentId: string;
  onClose: () => void;
  onCreateNewVersion: () => void;
  onSkip: () => void;
}

function CompareModal({
  open,
  paperlessDocumentId,
  inboxDocumentId,
  onClose,
  onCreateNewVersion,
  onSkip,
}: CompareModalProps) {
  const [paperlessUrl, setPaperlessUrl] = useState<string | null>(null);
  const [inboxUrl, setInboxUrl] = useState<string | null>(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    if (!open || paperlessDocumentId === null) return;
    let cancelled = false;
    let papUrl: string | null = null;
    let inbUrl: string | null = null;
    setLoading(true);
    (async () => {
      try {
        const [pBlob, iBlob] = await Promise.all([
          paperlessApi.getDocumentPdfBlob(paperlessDocumentId),
          inboxApi.previewBlob(inboxDocumentId),
        ]);
        if (cancelled) return;
        papUrl = URL.createObjectURL(pBlob);
        inbUrl = URL.createObjectURL(iBlob);
        setPaperlessUrl(papUrl);
        setInboxUrl(inbUrl);
      } catch {
        if (!cancelled) message.error('Vorschau konnte nicht geladen werden');
      } finally {
        if (!cancelled) setLoading(false);
      }
    })();
    return () => {
      cancelled = true;
      if (papUrl) URL.revokeObjectURL(papUrl);
      if (inbUrl) URL.revokeObjectURL(inbUrl);
      setPaperlessUrl(null);
      setInboxUrl(null);
    };
  }, [open, paperlessDocumentId, inboxDocumentId]);

  return (
    <Modal
      open={open}
      title="Duplikat vergleichen"
      onCancel={onClose}
      width="90vw"
      style={{ top: 20 }}
      footer={[
        <Button key="skip" onClick={onSkip}>
          Überspringen
        </Button>,
        <Button key="new" type="primary" onClick={onCreateNewVersion}>
          Neue Version anlegen
        </Button>,
      ]}
    >
      <div style={{ display: 'flex', gap: 12, height: '75vh' }}>
        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0 }}>
          <Typography.Text strong style={{ marginBottom: 4 }}>
            Original (Paperless)
          </Typography.Text>
          <div style={{ flex: 1, border: '1px solid #d9d9d9', borderRadius: 4, overflow: 'hidden' }}>
            {loading || !paperlessUrl ? (
              <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100%' }}>
                <Spin />
              </div>
            ) : (
              <iframe src={paperlessUrl} title="Paperless Original" style={{ width: '100%', height: '100%', border: 0 }} />
            )}
          </div>
        </div>
        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0 }}>
          <Typography.Text strong style={{ marginBottom: 4 }}>
            Aktueller Abschnitt (Inbox)
          </Typography.Text>
          <div style={{ flex: 1, border: '1px solid #d9d9d9', borderRadius: 4, overflow: 'hidden' }}>
            {loading || !inboxUrl ? (
              <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100%' }}>
                <Spin />
              </div>
            ) : (
              <iframe src={inboxUrl} title="Inbox Abschnitt" style={{ width: '100%', height: '100%', border: 0 }} />
            )}
          </div>
        </div>
      </div>
    </Modal>
  );
}

type WizardStepStatus = 'pending' | 'processing' | 'success' | 'duplicate' | 'error' | 'skipped';

interface WizardStep {
  status: WizardStepStatus;
  message?: string;
  results?: PostprocessActionResult[];
}

type DeleteStepStatus = 'pending' | 'awaiting' | 'deleting' | 'done' | 'blocked';

interface PostprocessWizardModalProps {
  open: boolean;
  documentId: string;
  documents: DocumentSegment[];
  onClose: () => void;
  onDeleted: () => void;
}

function PostprocessWizardModal({
  open,
  documentId,
  documents,
  onClose,
  onDeleted,
}: PostprocessWizardModalProps) {
  const [steps, setSteps] = useState<WizardStep[]>([]);
  const [currentSection, setCurrentSection] = useState(0);
  const [awaitingDecision, setAwaitingDecision] = useState(false);
  const [finished, setFinished] = useState(false);
  const [busy, setBusy] = useState(false);
  const [deleteStatus, setDeleteStatus] = useState<DeleteStepStatus>('pending');
  const [compareForSection, setCompareForSection] = useState<number | null>(null);

  const sectionCount = documents.length;

  useEffect(() => {
    if (open) {
      setSteps(documents.map(() => ({ status: 'pending' as WizardStepStatus })));
      setCurrentSection(0);
      setAwaitingDecision(false);
      setFinished(false);
      setBusy(false);
      setDeleteStatus('pending');
      setCompareForSection(null);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [open, sectionCount]);

  useEffect(() => {
    if (!finished) return;
    const allDone = steps.length > 0 && steps.every((s) => s.status === 'success' || s.status === 'skipped');
    setDeleteStatus(allDone ? 'awaiting' : 'blocked');
  }, [finished, steps]);

  const setStepAt = (idx: number, patch: Partial<WizardStep> | WizardStep) => {
    setSteps((prev) => prev.map((s, i) => (i === idx ? { ...s, ...patch } as WizardStep : s)));
  };

  const processSection = async (idx: number, replaceDuplicate = false) => {
    if (!documentId) return;
    setBusy(true);
    setStepAt(idx, { status: 'processing', message: undefined });
    try {
      const { results } = await inboxApi.postprocess(documentId, {
        sectionOffset: idx,
        processOnlyOne: true,
        replaceDuplicate,
      });
      const skipped = results.find((r) => r.skipped);
      const failed = results.filter((r) => !r.ok);
      if (skipped) {
        setStepAt(idx, { status: 'duplicate', message: skipped.message ?? 'Duplikat erkannt', results });
        setAwaitingDecision(true);
      } else if (failed.length > 0) {
        const msg = failed.map((f) => f.message ?? f.actionType).join(', ');
        setStepAt(idx, { status: 'error', message: msg, results });
        setAwaitingDecision(true);
      } else if (results.length === 0) {
        setStepAt(idx, { status: 'error', message: 'Keine aktive Aktion konfiguriert', results });
        setAwaitingDecision(true);
      } else {
        setStepAt(idx, { status: 'success', results });
        setCurrentSection((s) => s + 1);
      }
    } catch {
      setStepAt(idx, { status: 'error', message: 'Netzwerkfehler' });
      setAwaitingDecision(true);
    } finally {
      setBusy(false);
    }
  };

  useEffect(() => {
    if (!open || awaitingDecision || finished || busy) return;
    if (currentSection >= sectionCount) {
      setFinished(true);
      return;
    }
    void processSection(currentSection);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [open, currentSection, awaitingDecision, finished, busy, sectionCount]);

  const handleReplace = () => {
    setAwaitingDecision(false);
    void processSection(currentSection, true);
  };

  const handleSkip = () => {
    setSteps((prev) =>
      prev.map((s, i) =>
        i === currentSection
          ? { ...s, status: 'skipped' as WizardStepStatus, message: s.message ? `${s.message} (übersprungen)` : 'Übersprungen' }
          : s,
      ),
    );
    setAwaitingDecision(false);
    setCurrentSection((s) => s + 1);
  };

  const handleConfirmDelete = async () => {
    setDeleteStatus('deleting');
    try {
      await inboxApi.remove(documentId);
      setDeleteStatus('done');
      message.success('Dokument gelöscht');
      setTimeout(() => onDeleted(), 600);
    } catch {
      message.error('Löschen fehlgeschlagen');
      setDeleteStatus('awaiting');
    }
  };

  const handleSkipDelete = () => {
    onClose();
  };

  const stepItems = documents.map((doc, idx) => {
    const step = steps[idx] ?? { status: 'pending' as WizardStepStatus };
    const firstPage = doc.pages[0];
    const lastPage = doc.pages[doc.pages.length - 1];
    const pageRange = firstPage === lastPage ? `Seite ${firstPage}` : `Seiten ${firstPage}–${lastPage}`;

    let antStatus: 'wait' | 'process' | 'finish' | 'error' = 'wait';
    let icon: ReactNode | undefined;
    if (step.status === 'processing') {
      antStatus = 'process';
      icon = <LoadingOutlined />;
    } else if (step.status === 'success') {
      antStatus = 'finish';
    } else if (step.status === 'duplicate' || step.status === 'error') {
      antStatus = 'error';
    } else if (step.status === 'skipped') {
      antStatus = 'wait';
    }

    const actionLabels: Record<string, string> = {
      PAPERLESS: 'An Paperless gesendet',
      MAIL: 'Per E-Mail versendet',
      EXPORT: 'Exportiert',
    };
    const successLabel = step.results && step.results.length > 0
      ? [...new Set(step.results.map((r) => actionLabels[r.actionType] ?? r.actionType))].join(', ')
      : 'Verarbeitet';

    let description: ReactNode = <span style={{ color: '#999' }}>{pageRange}</span>;
    if (step.status === 'processing') {
      description = (
        <Space direction="vertical" size={2}>
          <span style={{ color: '#999' }}>{pageRange}</span>
          <span>Wird verarbeitet …</span>
        </Space>
      );
    } else if (step.status === 'success') {
      description = (
        <Space direction="vertical" size={2}>
          <span style={{ color: '#999' }}>{pageRange}</span>
          <span style={{ color: '#52c41a' }}>{successLabel}</span>
        </Space>
      );
    } else if (step.status === 'duplicate') {
      const dupDocId = step.results?.find((r) => r.duplicateOfDocumentId)?.duplicateOfDocumentId ?? null;
      description = (
        <Space direction="vertical" size={4}>
          <span style={{ color: '#999' }}>{pageRange}</span>
          <span style={{ color: '#faad14' }}>{step.message ?? 'Duplikat erkannt'}</span>
          {idx === currentSection && awaitingDecision && (
            <Space wrap>
              <Button type="primary" size="small" onClick={handleReplace}>
                Neue Version erstellen
              </Button>
              {dupDocId !== null && (
                <Button size="small" onClick={() => setCompareForSection(idx)}>
                  Vergleichen
                </Button>
              )}
              <Button size="small" onClick={handleSkip}>
                Überspringen
              </Button>
            </Space>
          )}
        </Space>
      );
    } else if (step.status === 'error') {
      description = (
        <Space direction="vertical" size={4}>
          <span style={{ color: '#999' }}>{pageRange}</span>
          <span style={{ color: '#ff4d4f' }}>{step.message ?? 'Fehler'}</span>
          {idx === currentSection && awaitingDecision && (
            <Button size="small" onClick={handleSkip}>
              Überspringen
            </Button>
          )}
        </Space>
      );
    } else if (step.status === 'skipped') {
      description = (
        <Space direction="vertical" size={2}>
          <span style={{ color: '#999' }}>{pageRange}</span>
          <span style={{ color: '#999' }}>{step.message ?? 'Übersprungen'}</span>
        </Space>
      );
    }

    return {
      title: `Abschnitt ${idx + 1}`,
      description,
      status: antStatus,
      icon,
    };
  });

  // Lösch-Schritt am Ende anhängen
  let deleteAntStatus: 'wait' | 'process' | 'finish' | 'error' = 'wait';
  let deleteIcon: ReactNode | undefined;
  let deleteDescription: ReactNode = (
    <span style={{ color: '#999' }}>Wird angeboten, sobald alle Abschnitte erfolgreich sind</span>
  );

  if (deleteStatus === 'blocked') {
    deleteAntStatus = 'error';
    deleteDescription = (
      <span style={{ color: '#999' }}>Nicht möglich – keine Abschnitte verarbeitet</span>
    );
  } else if (deleteStatus === 'awaiting') {
    deleteAntStatus = 'process';
    deleteDescription = (
      <Space direction="vertical" size={4}>
        <span>Soll das Dokument jetzt aus der Inbox entfernt werden?</span>
        <Space>
          <Popconfirm
            title="Dokument wirklich löschen?"
            description="Datei und Datenbank-Eintrag werden entfernt."
            okText="Ja, löschen"
            okButtonProps={{ danger: true }}
            cancelText="Abbrechen"
            onConfirm={handleConfirmDelete}
          >
            <Button type="primary" danger size="small" icon={<DeleteOutlined />}>
              Ja, löschen
            </Button>
          </Popconfirm>
          <Button size="small" onClick={handleSkipDelete}>
            Nein, behalten
          </Button>
        </Space>
      </Space>
    );
  } else if (deleteStatus === 'deleting') {
    deleteAntStatus = 'process';
    deleteIcon = <LoadingOutlined />;
    deleteDescription = <span>Wird gelöscht …</span>;
  } else if (deleteStatus === 'done') {
    deleteAntStatus = 'finish';
    deleteDescription = <span style={{ color: '#52c41a' }}>Dokument gelöscht</span>;
  }

  const allItems = [
    ...stepItems,
    {
      title: 'Dokument löschen',
      description: deleteDescription,
      status: deleteAntStatus,
      icon: deleteIcon,
    },
  ];

  const stepperCurrent = finished ? sectionCount : currentSection;

  return (
    <Modal
      open={open}
      title="Weiterverarbeitung"
      onCancel={onClose}
      footer={[
        <Button key="close" onClick={onClose}>
          {finished ? 'Schließen' : 'Abbrechen'}
        </Button>,
      ]}
      maskClosable={false}
      width={680}
      destroyOnClose
    >
      {documents.length === 0 ? (
        <Empty description="Keine Abschnitte erkannt" />
      ) : (
        <Steps direction="vertical" current={stepperCurrent} items={allItems} />
      )}
      <CompareModal
        open={compareForSection !== null}
        paperlessDocumentId={
          compareForSection !== null
            ? steps[compareForSection]?.results?.find((r) => r.duplicateOfDocumentId)?.duplicateOfDocumentId ?? null
            : null
        }
        inboxDocumentId={documentId}
        onClose={() => setCompareForSection(null)}
        onCreateNewVersion={() => {
          // TODO: wird im nächsten Schritt implementiert
        }}
        onSkip={() => {
          setCompareForSection(null);
          handleSkip();
        }}
      />
    </Modal>
  );
}


interface DownloadSegmentsDialogProps {
  open: boolean;
  fileId: string;
  fileName: string;
  documents: DocumentSegment[];
  onClose: () => void;
}

function DownloadSegmentsDialog({ open, fileId, fileName, documents, onClose }: DownloadSegmentsDialogProps) {
  const [filenames, setFilenames] = useState<string[]>([]);
  const [downloading, setDownloading] = useState<number | 'all' | null>(null);

  useEffect(() => {
    if (!open) return;
    const base = fileName.replace(/\.pdf$/i, '');
    setFilenames(
      documents.map((doc) =>
        doc.belegname || (documents.length === 1 ? base : `${base}_${doc.index + 1}`),
      ),
    );
    setDownloading(null);
  }, [open, documents, fileName]);

  const triggerDownload = (blob: Blob, name: string) => {
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = name.endsWith('.pdf') ? name : `${name}.pdf`;
    a.click();
    URL.revokeObjectURL(url);
  };

  const downloadOne = async (idx: number) => {
    setDownloading(idx);
    try {
      const blob = await inboxApi.downloadSegmentBlob(fileId, documents[idx].pages);
      triggerDownload(blob, filenames[idx] || fileName);
    } catch {
      message.error('Download fehlgeschlagen');
    } finally {
      setDownloading(null);
    }
  };

  const downloadAll = async () => {
    setDownloading('all');
    try {
      for (let i = 0; i < documents.length; i++) {
        const blob = await inboxApi.downloadSegmentBlob(fileId, documents[i].pages);
        triggerDownload(blob, filenames[i] || fileName);
        if (i < documents.length - 1) await new Promise((r) => setTimeout(r, 300));
      }
    } catch {
      message.error('Download fehlgeschlagen');
    } finally {
      setDownloading(null);
    }
  };

  return (
    <Modal
      open={open}
      title="Dokumente herunterladen"
      onCancel={onClose}
      footer={[
        <Button key="close" onClick={onClose}>
          Schließen
        </Button>,
        <Button key="all" type="primary" icon={<SaveOutlined />} loading={downloading === 'all'} disabled={downloading !== null && downloading !== 'all'} onClick={downloadAll}>
          Alle herunterladen
        </Button>,
      ]}
      width={560}
      destroyOnClose
    >
      <div style={{ display: 'flex', flexDirection: 'column', gap: 10, marginTop: 16 }}>
        {documents.map((doc, i) => {
          const first = doc.pages[0];
          const last = doc.pages[doc.pages.length - 1];
          const range = first === last ? `Seite ${first}` : `Seiten ${first}–${last}`;
          return (
            <div key={doc.index} style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
              <span style={{ minWidth: 90, color: '#888', fontSize: 12 }}>{range}</span>
              <Input
                value={filenames[i] ?? ''}
                onChange={(e) =>
                  setFilenames((prev) => prev.map((f, j) => (j === i ? e.target.value : f)))
                }
                suffix=".pdf"
                style={{ flex: 1 }}
              />
              <Button
                icon={<SaveOutlined />}
                loading={downloading === i}
                disabled={downloading !== null && downloading !== i}
                onClick={() => downloadOne(i)}
              >
                Laden
              </Button>
            </div>
          );
        })}
      </div>
    </Modal>
  );
}

function TiptapToolbar({ editor }: { editor: ReturnType<typeof useEditor> }) {
  if (!editor) return null;
  const btnStyle = (active: boolean): React.CSSProperties => ({
    padding: '2px 8px',
    border: '1px solid #d9d9d9',
    borderRadius: 4,
    cursor: 'pointer',
    background: active ? '#e6f4ff' : '#fff',
    fontWeight: active ? 600 : 400,
  });
  return (
    <div style={{ display: 'flex', gap: 4, padding: '4px 0', borderBottom: '1px solid #f0f0f0', marginBottom: 6, flexWrap: 'wrap' }}>
      <button style={btnStyle(editor.isActive('bold'))} onMouseDown={(e) => { e.preventDefault(); editor.chain().focus().toggleBold().run(); }}>F</button>
      <button style={{ ...btnStyle(editor.isActive('italic')), fontStyle: 'italic' }} onMouseDown={(e) => { e.preventDefault(); editor.chain().focus().toggleItalic().run(); }}>K</button>
      <button style={{ ...btnStyle(editor.isActive('underline')), textDecoration: 'underline' }} onMouseDown={(e) => { e.preventDefault(); editor.chain().focus().toggleUnderline().run(); }}>U</button>
      <button style={btnStyle(editor.isActive('bulletList'))} onMouseDown={(e) => { e.preventDefault(); editor.chain().focus().toggleBulletList().run(); }}>• Liste</button>
      <button style={btnStyle(editor.isActive('orderedList'))} onMouseDown={(e) => { e.preventDefault(); editor.chain().focus().toggleOrderedList().run(); }}>1. Liste</button>
    </div>
  );
}

interface SendEmailDialogProps {
  open: boolean;
  fileId: string;
  fileName: string;
  documents: DocumentSegment[];
  onClose: () => void;
}

function SendEmailDialog({ open, fileId, fileName, documents, onClose }: SendEmailDialogProps) {
  const [form] = Form.useForm();
  const [submitting, setSubmitting] = useState(false);
  const [filenames, setFilenames] = useState<string[]>([]);

  const editor = useEditor({
    extensions: [StarterKit, Underline],
    content: '',
  });

  useEffect(() => {
    if (!open) return;
    form.resetFields();
    editor?.commands.clearContent();
    const base = fileName.replace(/\.pdf$/i, '');
    setFilenames(
      documents.map((doc) =>
        doc.belegname || (documents.length === 1 ? base : `${base}_${doc.index + 1}`),
      ),
    );
  }, [open, documents, fileName, form, editor]);

  const handleOk = async () => {
    try {
      const values = await form.validateFields();
      setSubmitting(true);
      await inboxApi.sendEmail(fileId, {
        to: values.to,
        subject: values.subject,
        body: editor?.getText() ?? '',
        html: editor?.getHTML(),
        segments: documents.map((doc, i) => ({
          pages: doc.pages,
          filename: filenames[i] || fileName,
        })),
      });
      message.success('E-Mail wurde gesendet');
      onClose();
    } catch (err: any) {
      if (err?.errorFields) return;
      message.error('E-Mail konnte nicht gesendet werden');
    } finally {
      setSubmitting(false);
    }
  };

  return (
    <Modal
      open={open}
      title="Als E-Mail-Anhang versenden"
      onCancel={onClose}
      onOk={handleOk}
      okText="Senden"
      cancelText="Abbrechen"
      confirmLoading={submitting}
      destroyOnClose
      width={580}
    >
      <Form form={form} layout="vertical" style={{ marginTop: 16 }}>
        <Form.Item name="to" label="Empfänger" rules={[{ required: true, message: 'Bitte Empfänger angeben' }, { type: 'email', message: 'Ungültige E-Mail-Adresse' }]}>
          <Input placeholder="empfaenger@beispiel.de" />
        </Form.Item>
        <Form.Item name="subject" label="Betreff" rules={[{ required: true, message: 'Bitte Betreff angeben' }]}>
          <Input />
        </Form.Item>
        <Form.Item label="Nachricht">
          <div style={{ border: '1px solid #d9d9d9', borderRadius: 6, padding: '6px 10px', minHeight: 160 }}>
            <TiptapToolbar editor={editor} />
            <EditorContent editor={editor} style={{ minHeight: 120, outline: 'none' }} />
          </div>
        </Form.Item>
        <Form.Item label="Anhänge">
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            {documents.map((doc, i) => {
              const first = doc.pages[0];
              const last = doc.pages[doc.pages.length - 1];
              const range = first === last ? `Seite ${first}` : `Seiten ${first}–${last}`;
              return (
                <div key={doc.index} style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
                  <span style={{ minWidth: 90, color: '#888', fontSize: 12 }}>{range}</span>
                  <Input
                    value={filenames[i] ?? ''}
                    onChange={(e) =>
                      setFilenames((prev) => prev.map((f, j) => (j === i ? e.target.value : f)))
                    }
                    suffix=".pdf"
                  />
                </div>
              );
            })}
          </div>
        </Form.Item>
      </Form>
    </Modal>
  );
}

export default function InboxDetailPage() {
  const { id } = useParams<{ id: string }>();
  const navigate = useNavigate();
  const [file, setFile] = useState<InboxFile | null>(null);
  const [loading, setLoading] = useState(true);
  const [thumbUrls, setThumbUrls] = useState<Map<number, string>>(new Map());
  const [previewUrl, setPreviewUrl] = useState<string | null>(null);
  const [selectedPage, setSelectedPage] = useState(1);
  const [zoom, setZoom] = useState(1);
  const [wizardOpen, setWizardOpen] = useState(false);
  const [downloadDialogOpen, setDownloadDialogOpen] = useState(false);
  const [emailDialogOpen, setEmailDialogOpen] = useState(false);
  const [scanMode, setScanMode] = useState(false);
  const [scanning, setScanning] = useState(false);
  const [dragStart, setDragStart] = useState<{ clientX: number; clientY: number; relX: number; relY: number } | null>(null);
  const [dragEnd, setDragEnd] = useState<{ relX: number; relY: number } | null>(null);

  const thumbsRef = useRef<Map<number, string>>(new Map());
  const previewRef = useRef<string | null>(null);
  const imgRef = useRef<HTMLImageElement>(null);
  const overlayRef = useRef<HTMLDivElement>(null);

  const rotationFor = (page: number): number =>
    file?.rotations?.[String(page)] ?? 0;
  const currentRotation = rotationFor(selectedPage);

  useEffect(() => {
    if (!id) return;
    let cancelled = false;
    setLoading(true);
    (async () => {
      try {
        const list = await inboxApi.list();
        if (cancelled) return;
        const found = list.find((f) => f.id === id) ?? null;
        setFile(found);
        if (!found) message.error('Datei nicht gefunden');
      } catch {
        if (!cancelled) message.error('Datei konnte nicht geladen werden');
      } finally {
        if (!cancelled) setLoading(false);
      }
    })();
    return () => {
      cancelled = true;
    };
  }, [id]);

  const documents = useMemo<DocumentSegment[]>(() => {
    if (!file) return [];
    const splitPages = file.barcodes
      .filter((b) => b.splitBefore)
      .map((b) => b.page);
    return buildDocuments(file.pageCount, splitPages, file.deletedPages, file.manualSplitPages, file.barcodes);
  }, [file]);

  const effectivePages = useMemo<number[]>(() => {
    if (!file) return [];
    const deleted = new Set(file.deletedPages);
    return Array.from({ length: file.pageCount }, (_, i) => i + 1).filter(
      (p) => !deleted.has(p),
    );
  }, [file]);

  const selectedDocIndex = useMemo(() => {
    if (documents.length === 0) return 0;
    const idx = documents.findIndex((d) => d.pages.includes(selectedPage));
    return idx >= 0 ? idx : 0;
  }, [documents, selectedPage]);

  // Falls die aktuell ausgewählte Seite verschwindet (z. B. nach Mark-as-deleted
  // oder beim ersten Laden), auf erste verfügbare Seite springen.
  useEffect(() => {
    if (effectivePages.length === 0) return;
    if (!effectivePages.includes(selectedPage)) {
      setSelectedPage(effectivePages[0]);
    }
  }, [effectivePages, selectedPage]);

  useEffect(() => {
    if (!file || file.pageCount === 0) return;
    let cancelled = false;
    const fileId = file.id;
    const pageCount = file.pageCount;

    (async () => {
      const pages = Array.from({ length: pageCount }, (_, i) => i + 1);
      const results = await Promise.all(
        pages.map(async (n) => {
          try {
            const blob = await inboxApi.thumbnailBlob(fileId, n);
            return { page: n, url: URL.createObjectURL(blob) };
          } catch {
            return null;
          }
        }),
      );
      if (cancelled) {
        for (const r of results) if (r) URL.revokeObjectURL(r.url);
        return;
      }
      const map = new Map<number, string>();
      for (const r of results) if (r) map.set(r.page, r.url);
      thumbsRef.current = map;
      setThumbUrls(map);
    })();

    return () => {
      cancelled = true;
      const current = thumbsRef.current;
      thumbsRef.current = new Map();
      setThumbUrls(new Map());
      for (const url of current.values()) URL.revokeObjectURL(url);
    };
  }, [file?.id, file?.pageCount]);

  useEffect(() => {
    setZoom(1);
  }, [selectedPage]);

  const handlePrev = () => {
    const i = effectivePages.indexOf(selectedPage);
    if (i > 0) setSelectedPage(effectivePages[i - 1]);
  };
  const handleNext = () => {
    const i = effectivePages.indexOf(selectedPage);
    if (i >= 0 && i < effectivePages.length - 1) {
      setSelectedPage(effectivePages[i + 1]);
    }
  };
  const handleZoomIn = () => setZoom((z) => Math.min(ZOOM_MAX, +(z + ZOOM_STEP).toFixed(2)));
  const handleZoomOut = () => setZoom((z) => Math.max(ZOOM_MIN, +(z - ZOOM_STEP).toFixed(2)));

  const applyRotation = async (delta: number) => {
    if (!file) return;
    const target = selectedPage;
    const next = (((rotationFor(target) + delta) % 360) + 360) % 360;
    try {
      await inboxApi.setPageRotation(file.id, target, next);
      const list = await inboxApi.list();
      const refreshed = list.find((f) => f.id === file.id) ?? null;
      if (refreshed) setFile(refreshed);
    } catch {
      message.error('Rotation konnte nicht gespeichert werden');
    }
  };
  const handleRotateLeft = () => applyRotation(-90);
  const handleRotateRight = () => applyRotation(90);

  const handleDeletePage = async () => {
    if (!file) return;
    const target = selectedPage;
    try {
      await inboxApi.removePage(file.id, target);
      const list = await inboxApi.list();
      const refreshed = list.find((f) => f.id === file.id) ?? null;
      if (!refreshed) {
        navigate('/inbox');
        return;
      }

      const newDeleted = new Set(refreshed.deletedPages);
      const allPages = Array.from({ length: refreshed.pageCount }, (_, i) => i + 1);
      const newEffective = allPages.filter((p) => !newDeleted.has(p));
      const nextPage =
        newEffective.find((p) => p > target) ??
        [...newEffective].reverse().find((p) => p < target) ??
        newEffective[0] ??
        1;

      setFile(refreshed);
      setSelectedPage(nextPage);
      message.success(`Seite zur Löschung markiert`);
    } catch (err: any) {
      if (err?.response?.status === 409) {
        message.warning('Mindestens eine Seite muss übrig bleiben');
      } else {
        message.error('Markieren fehlgeschlagen');
      }
    }
  };


  const handleToggleSplit = async () => {
    if (!file) return;
    try {
      await inboxApi.toggleSplit(file.id, selectedPage);
      const list = await inboxApi.list();
      const refreshed = list.find((f) => f.id === file.id) ?? null;
      if (refreshed) setFile(refreshed);
    } catch {
      message.error('Trennung konnte nicht gespeichert werden');
    }
  };

  const handleResetEdits = async () => {
    if (!file) return;
    try {
      await inboxApi.resetEdits(file.id);
      const list = await inboxApi.list();
      const refreshed = list.find((f) => f.id === file.id) ?? null;
      if (refreshed) setFile(refreshed);
      message.success('Bearbeitungen zurückgesetzt');
    } catch {
      message.error('Zurücksetzen fehlgeschlagen');
    }
  };

  const toNormalizedImageCoords = useCallback((clientX: number, clientY: number) => {
    const img = imgRef.current;
    if (!img) return null;
    const rect = img.getBoundingClientRect();
    const cx = rect.left + rect.width / 2;
    const cy = rect.top + rect.height / 2;
    const dx = clientX - cx;
    const dy = clientY - cy;
    const dxU = dx / zoom;
    const dyU = dy / zoom;
    const Rrad = currentRotation * Math.PI / 180;
    const cosR = Math.cos(Rrad);
    const sinR = Math.sin(Rrad);
    const dxUr = dxU * cosR + dyU * sinR;
    const dyUr = -dxU * sinR + dyU * cosR;
    const rW = (currentRotation === 90 || currentRotation === 270) ? rect.height / zoom : rect.width / zoom;
    const rH = (currentRotation === 90 || currentRotation === 270) ? rect.width / zoom : rect.height / zoom;
    return {
      x: Math.max(0, Math.min(1, (dxUr + rW / 2) / rW)),
      y: Math.max(0, Math.min(1, (dyUr + rH / 2) / rH)),
    };
  }, [zoom, currentRotation]);

  const handleOverlayMouseDown = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
    e.preventDefault();
    const overlayRect = e.currentTarget.getBoundingClientRect();
    setDragStart({ clientX: e.clientX, clientY: e.clientY, relX: e.clientX - overlayRect.left, relY: e.clientY - overlayRect.top });
    setDragEnd(null);
  }, []);

  const handleOverlayMouseMove = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
    if (!dragStart) return;
    const overlayRect = e.currentTarget.getBoundingClientRect();
    setDragEnd({ relX: e.clientX - overlayRect.left, relY: e.clientY - overlayRect.top });
  }, [dragStart]);

  const handleOverlayMouseUp = useCallback(async (e: React.MouseEvent<HTMLDivElement>) => {
    if (!dragStart || !file) { setDragStart(null); setDragEnd(null); return; }
    const overlayRect = e.currentTarget.getBoundingClientRect();
    const end = { clientX: e.clientX, clientY: e.clientY, relX: e.clientX - overlayRect.left, relY: e.clientY - overlayRect.top };
    setDragStart(null);
    setDragEnd(null);
    setScanMode(false);

    const p1 = toNormalizedImageCoords(dragStart.clientX, dragStart.clientY);
    const p2 = toNormalizedImageCoords(end.clientX, end.clientY);
    if (!p1 || !p2) return;

    const rx = Math.min(p1.x, p2.x);
    const ry = Math.min(p1.y, p2.y);
    const rw = Math.abs(p2.x - p1.x);
    const rh = Math.abs(p2.y - p1.y);
    if (rw < 0.01 || rh < 0.01) { message.warning('Bitte einen größeren Bereich auswählen'); return; }

    setScanning(true);
    try {
      const result = await inboxApi.scanRegion(file.id, selectedPage, { x: rx, y: ry, w: rw, h: rh });
      if (result.found.length > 0) {
        message.success(`QR-Code gefunden: ${result.found.join(', ')}`);
        const list = await inboxApi.list();
        const refreshed = list.find((f) => f.id === file.id) ?? null;
        if (refreshed) setFile(refreshed);
      } else {
        message.warning('Kein QR-Code in diesem Bereich gefunden');
      }
    } catch {
      message.error('QR-Bereich-Scan fehlgeschlagen');
    } finally {
      setScanning(false);
    }
  }, [dragStart, file, selectedPage, toNormalizedImageCoords]);

  const handleOverlayMouseLeave = useCallback(() => {
    setDragStart(null);
    setDragEnd(null);
    setScanMode(false);
  }, []);

  useEffect(() => {
    if (!file) return;
    let cancelled = false;
    (async () => {
      try {
        const blob = await inboxApi.pagePreviewBlob(file.id, selectedPage);
        if (cancelled) return;
        const url = URL.createObjectURL(blob);
        if (previewRef.current) URL.revokeObjectURL(previewRef.current);
        previewRef.current = url;
        setPreviewUrl(url);
      } catch {
        // silent
      }
    })();
    return () => {
      cancelled = true;
    };
  }, [file?.id, selectedPage]);

  useEffect(
    () => () => {
      if (previewRef.current) {
        URL.revokeObjectURL(previewRef.current);
        previewRef.current = null;
      }
    },
    [],
  );

  if (loading) {
    return <Spin size="large" style={{ display: 'block', margin: '100px auto' }} />;
  }

  if (!file) {
    return (
      <div>
        <Button
          icon={<ArrowLeftOutlined />}
          onClick={() => navigate('/inbox')}
          style={{ marginBottom: 16 }}
        >
          Zurück
        </Button>
        <Empty description="Datei nicht gefunden" />
      </div>
    );
  }

  const currentDoc = documents[selectedDocIndex];
  const sidebarPages = currentDoc?.pages ?? [];
  const effectiveIndex = effectivePages.indexOf(selectedPage);
  const canPrev = effectiveIndex > 0;
  const canNext = effectiveIndex >= 0 && effectiveIndex < effectivePages.length - 1;
  const canDelete = effectivePages.length > 1;
  const isSplitPage = file.manualSplitPages.includes(selectedPage);
  const canSplit = selectedPage !== currentDoc?.pages[0];
  const rotationCount = Object.keys(file.rotations ?? {}).length;
  const manualSplitCount = file.manualSplitPages.length;
  const pendingEdits = file.deletedPages.length + rotationCount + manualSplitCount;
  const editsLabel = (() => {
    const parts: string[] = [];
    if (file.deletedPages.length > 0) parts.push(`${file.deletedPages.length} zur Löschung markiert`);
    if (rotationCount > 0) parts.push(`${rotationCount} gedreht`);
    if (manualSplitCount > 0) parts.push(`${manualSplitCount} manuell getrennt`);
    return parts.join(' · ');
  })();

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: 'calc(100vh - 120px)' }}>
      <div
        style={{
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'space-between',
          marginBottom: 12,
          gap: 12,
        }}
      >
        <Space>
          <Button icon={<ArrowLeftOutlined />} onClick={() => navigate('/inbox')}>
            Zurück
          </Button>
          <Title level={4} style={{ margin: 0 }}>
            {file.name}
          </Title>
          <SourceTag source={file.source} />
        </Space>
        <Dropdown.Button
          type="primary"
          icon={<DownOutlined />}
          disabled={documents.length === 0}
          onClick={() => setWizardOpen(true)}
          menu={{
            items: [
              { key: 'save', label: 'Speichern', icon: <SaveOutlined /> },
              { key: 'email', label: 'Als E-Mail-Anhang versenden', icon: <MailOutlined /> },
            ] as MenuProps['items'],
            onClick: ({ key }) => {
              if (key === 'save') {
                setDownloadDialogOpen(true);
              }
              if (key === 'email') setEmailDialogOpen(true);
            },
          }}
        >
          <ThunderboltOutlined /> Weiterverarbeiten
        </Dropdown.Button>
      </div>

      {pendingEdits > 0 && (
        <div
          style={{
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'space-between',
            padding: '6px 12px',
            background: '#fffbe6',
            border: '1px solid #ffe58f',
            borderRadius: 8,
            marginBottom: 12,
          }}
        >
          <Typography.Text>
            {editsLabel}
            <Typography.Text type="secondary" style={{ marginLeft: 8 }}>
              (wird erst bei der Weiterverarbeitung angewendet)
            </Typography.Text>
          </Typography.Text>
          <Button size="small" type="link" onClick={handleResetEdits}>
            Zurücksetzen
          </Button>
        </div>
      )}

      <div
        style={{
          display: 'flex',
          gap: 8,
          padding: 8,
          background: '#fafafa',
          border: '1px solid #f0f0f0',
          borderRadius: 8,
          overflowX: 'auto',
          marginBottom: 12,
        }}
      >
        {documents.length === 0 ? (
          <Typography.Text type="secondary">Keine Seiten</Typography.Text>
        ) : (
          documents.map((doc) => {
            const active = doc.index === selectedDocIndex;
            const cover = doc.pages[0];
            const url = thumbUrls.get(cover);
            return (
              <div
                key={doc.index}
                style={{ flex: '0 0 auto', display: 'flex', flexDirection: 'column', alignItems: 'center' }}
              >
                {doc.belegname && (
                  <div
                    title={doc.belegname}
                    style={{
                      fontSize: 10,
                      color: '#555',
                      maxWidth: 92,
                      overflow: 'hidden',
                      textOverflow: 'ellipsis',
                      whiteSpace: 'nowrap',
                      marginBottom: 3,
                      textAlign: 'center',
                    }}
                  >
                    {doc.belegname}
                  </div>
                )}
              <div
                onClick={() => setSelectedPage(cover)}
                style={{
                  cursor: 'pointer',
                  padding: 2,
                  border: active ? '2px solid #1677ff' : '2px solid transparent',
                  borderRadius: 6,
                  position: 'relative',
                  width: 92,
                  height: 120,
                }}
              >
                <div
                  style={{
                    width: '100%',
                    height: '100%',
                    background: '#fff',
                    border: '1px solid #e0e0e0',
                    borderRadius: 4,
                    overflow: 'hidden',
                    display: 'flex',
                    alignItems: 'center',
                    justifyContent: 'center',
                  }}
                >
                  {url ? (
                    <img
                      src={url}
                      alt={`Dokument ${doc.index + 1}`}
                      style={thumbImageStyle(rotationFor(cover), 84)}
                    />
                  ) : (
                    <Spin size="small" />
                  )}
                </div>
                <span
                  style={{
                    position: 'absolute',
                    bottom: 4,
                    right: 4,
                    padding: '1px 6px',
                    fontSize: 11,
                    lineHeight: '14px',
                    background: 'rgba(0, 0, 0, 0.65)',
                    color: '#fff',
                    borderRadius: 8,
                  }}
                >
                  {doc.pages.length}
                </span>
              </div>
              </div>
            );
          })
        )}
      </div>

      <div
        style={{
          display: 'flex',
          flex: 1,
          minHeight: 0,
          gap: 8,
        }}
      >
        <div
          style={{
            width: 140,
            overflowY: 'auto',
            padding: 6,
            background: '#fafafa',
            border: '1px solid #f0f0f0',
            borderRadius: 8,
          }}
        >
          {sidebarPages.map((n, idx) => {
            const active = n === selectedPage;
            const url = thumbUrls.get(n);
            const docPage = idx + 1;
            return (
              <div
                key={n}
                onClick={() => setSelectedPage(n)}
                style={{
                  cursor: 'pointer',
                  marginBottom: 6,
                  padding: 2,
                  border: active ? '2px solid #1677ff' : '2px solid transparent',
                  borderRadius: 6,
                  background: '#fff',
                  position: 'relative',
                }}
              >
                <div
                  style={{
                    width: '100%',
                    height: 170,
                    display: 'flex',
                    alignItems: 'center',
                    justifyContent: 'center',
                    background: '#fff',
                  }}
                >
                  {url ? (
                    <img
                      src={url}
                      alt={`Seite ${docPage}`}
                      style={thumbImageStyle(rotationFor(n), 130)}
                    />
                  ) : (
                    <Spin size="small" />
                  )}
                </div>
                <span
                  style={{
                    position: 'absolute',
                    bottom: 4,
                    left: '50%',
                    transform: 'translateX(-50%)',
                    padding: '1px 6px',
                    fontSize: 11,
                    lineHeight: '14px',
                    background: 'rgba(0, 0, 0, 0.65)',
                    color: '#fff',
                    borderRadius: 8,
                  }}
                >
                  {docPage}
                </span>
              </div>
            );
          })}
        </div>

        <div
          style={{
            flex: 1,
            minWidth: 0,
            position: 'relative',
            background: '#fafafa',
            border: '1px solid #f0f0f0',
            borderRadius: 8,
            overflow: 'hidden',
          }}
        >
          <div
            style={{
              position: 'absolute',
              bottom: 16,
              left: '50%',
              transform: 'translateX(-50%)',
              zIndex: 10,
              display: 'flex',
              alignItems: 'center',
              gap: 6,
              padding: '6px 10px',
              background: 'rgba(50, 50, 50, 0.6)',
              backdropFilter: 'blur(20px) saturate(180%)',
              WebkitBackdropFilter: 'blur(20px) saturate(180%)',
              border: '1px solid rgba(255, 255, 255, 0.15)',
              borderRadius: 999,
              boxShadow: '0 4px 16px rgba(0, 0, 0, 0.25)',
              color: '#fff',
            }}
          >
            <Tooltip title="Vorherige Seite">
              <Button
                type="text"
                shape="circle"
                icon={<LeftOutlined style={{ fontSize: 16 }} />}
                onClick={handlePrev}
                disabled={!canPrev}
                style={{ color: '#fff' }}
              />
            </Tooltip>
            <Tooltip title="Nächste Seite">
              <Button
                type="text"
                shape="circle"
                icon={<RightOutlined style={{ fontSize: 16 }} />}
                onClick={handleNext}
                disabled={!canNext}
                style={{ color: '#fff' }}
              />
            </Tooltip>
            <span style={{ width: 1, height: 20, background: 'rgba(255,255,255,0.2)' }} />
            <Tooltip title="Reinzoomen">
              <Button
                type="text"
                shape="circle"
                icon={<ZoomInOutlined style={{ fontSize: 16 }} />}
                onClick={handleZoomIn}
                disabled={zoom >= ZOOM_MAX}
                style={{ color: '#fff' }}
              />
            </Tooltip>
            <Tooltip title="Rauszoomen">
              <Button
                type="text"
                shape="circle"
                icon={<ZoomOutOutlined style={{ fontSize: 16 }} />}
                onClick={handleZoomOut}
                disabled={zoom <= ZOOM_MIN}
                style={{ color: '#fff' }}
              />
            </Tooltip>
            <span style={{ width: 1, height: 20, background: 'rgba(255,255,255,0.2)' }} />
            <Tooltip title="90° nach links drehen">
              <Button
                type="text"
                shape="circle"
                icon={<UndoOutlined style={{ fontSize: 16 }} />}
                onClick={handleRotateLeft}
                style={{ color: '#fff' }}
              />
            </Tooltip>
            <Tooltip title="90° nach rechts drehen">
              <Button
                type="text"
                shape="circle"
                icon={<RedoOutlined style={{ fontSize: 16 }} />}
                onClick={handleRotateRight}
                style={{ color: '#fff' }}
              />
            </Tooltip>
            <span style={{ width: 1, height: 20, background: 'rgba(255,255,255,0.2)' }} />
            {canDelete ? (
              <Popconfirm
                title="Seite zur Löschung markieren?"
                description="Wird erst bei der Weiterverarbeitung tatsächlich entfernt."
                okText="Markieren"
                cancelText="Abbrechen"
                okButtonProps={{ danger: true }}
                onConfirm={handleDeletePage}
              >
                <Tooltip title="Seite zur Löschung markieren">
                  <Button
                    type="text"
                    shape="circle"
                    icon={<DeleteOutlined style={{ fontSize: 16 }} />}
                    style={{ color: '#ff7875' }}
                  />
                </Tooltip>
              </Popconfirm>
            ) : (
              <Tooltip title="Mindestens eine Seite muss übrig bleiben">
                <Button
                  type="text"
                  shape="circle"
                  icon={<DeleteOutlined style={{ fontSize: 16 }} />}
                  disabled
                  style={{ color: 'rgba(255,255,255,0.3)' }}
                />
              </Tooltip>
            )}
            <span style={{ width: 1, height: 20, background: 'rgba(255,255,255,0.2)' }} />
            {canSplit && (
              <Tooltip title={isSplitPage ? 'Manuelle Trennung aufheben' : 'Vor dieser Seite trennen'}>
                <Button
                  type="text"
                  shape="circle"
                  icon={<ScissorOutlined style={{ fontSize: 16 }} />}
                  onClick={handleToggleSplit}
                  style={{ color: isSplitPage ? '#ffd666' : '#fff' }}
                />
              </Tooltip>
            )}
            <Tooltip title={scanMode ? 'Bereich-Scan abbrechen' : 'QR-Code in Bereich scannen'}>
              <Button
                type="text"
                shape="circle"
                icon={scanning
                  ? <LoadingOutlined style={{ fontSize: 16 }} />
                  : <QrcodeOutlined style={{ fontSize: 16 }} />}
                onClick={() => { setScanMode((v) => !v); setDragStart(null); setDragEnd(null); }}
                disabled={scanning}
                style={{ color: scanMode ? '#52c41a' : '#fff' }}
              />
            </Tooltip>
          </div>

          <div
            style={{
              width: '100%',
              height: '100%',
              overflow: 'auto',
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              padding: 6,
            }}
          >
            {previewUrl ? (
              <img
                ref={imgRef}
                src={previewUrl}
                alt={`Vorschau Seite ${selectedPage}`}
                style={{
                  maxWidth: '100%',
                  maxHeight: '100%',
                  objectFit: 'contain',
                  transform: `rotate(${currentRotation}deg) scale(${zoom})`,
                  transformOrigin: 'center center',
                  transition: 'transform 0.15s ease-out',
                  boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
                  background: '#fff',
                }}
              />
            ) : (
              <Spin />
            )}
          </div>

          {/* Overlay für QR-Bereich-Scan */}
          <div
            ref={overlayRef}
            style={{
              position: 'absolute',
              inset: 0,
              zIndex: scanMode || dragStart ? 5 : -1,
              cursor: scanMode ? 'crosshair' : 'default',
              pointerEvents: scanMode ? 'all' : 'none',
            }}
            onMouseDown={handleOverlayMouseDown}
            onMouseMove={handleOverlayMouseMove}
            onMouseUp={handleOverlayMouseUp}
            onMouseLeave={handleOverlayMouseLeave}
          >
            {dragStart && dragEnd && (
              <div
                style={{
                  position: 'absolute',
                  left: Math.min(dragStart.relX, dragEnd.relX),
                  top: Math.min(dragStart.relY, dragEnd.relY),
                  width: Math.abs(dragEnd.relX - dragStart.relX),
                  height: Math.abs(dragEnd.relY - dragStart.relY),
                  border: '2px dashed #1677ff',
                  background: 'rgba(22, 119, 255, 0.1)',
                  pointerEvents: 'none',
                }}
              />
            )}
          </div>
        </div>
      </div>

      <PostprocessWizardModal
        open={wizardOpen}
        documentId={file.id}
        documents={documents}
        onClose={() => setWizardOpen(false)}
        onDeleted={() => navigate('/inbox')}
      />
      <DownloadSegmentsDialog
        open={downloadDialogOpen}
        fileId={file.id}
        fileName={file.name}
        documents={documents}
        onClose={() => setDownloadDialogOpen(false)}
      />
      <SendEmailDialog
        open={emailDialogOpen}
        fileId={file.id}
        fileName={file.name}
        documents={documents}
        onClose={() => setEmailDialogOpen(false)}
      />
    </div>
  );
}
