import React, { useEffect, useMemo, useState } from 'react';
import { useParams } from 'react-router-dom';
import { Box, Button, Divider, FormControlLabel, MenuItem, Select, Switch, TextField, Typography } from '@mui/material';
import { SelectChangeEvent } from '@mui/material/Select';
// import { CCFilesPanel } from '../../../utils/tldraw/ui-overrides/components/shared/CCFilesPanel';
import { CCDoclingViewer } from './CCDoclingViewer.tsx';
import CCEnhancedFilePanel from './CCEnhancedFilePanel.tsx';
import CCBundleViewer from './CCBundleViewer.tsx';
import { useAuth } from '../../../contexts/AuthContext';

type CanonicalDoclingConfig = {
  pipeline: 'standard' | 'vlm' | 'asr';
  pdf_backend: 'dlparse_v4' | 'pypdfium2' | 'dlparse_v1' | 'dlparse_v2';
  do_ocr: boolean;
  force_ocr: boolean;
  table_mode: 'fast' | 'accurate';
  do_picture_classification: boolean;
  do_picture_description: boolean;
  picture_description_prompt?: string;
  // Extended options
  target_type?: 'inbody' | 'zip';
  image_export_mode?: 'placeholder' | 'embedded' | 'referenced';
  table_cell_matching?: boolean;
  picture_description_local?: string; // JSON string per API
  picture_description_api?: string;   // JSON string per API
  vlm_pipeline_model?: string;
  vlm_pipeline_model_local?: string;  // JSON string per API
  vlm_pipeline_model_api?: string;    // JSON string per API
  to_formats?: string[];
  do_formula_enrichment?: boolean;
  do_code_enrichment?: boolean;
};

type CanonicalDoclingRequest = {
  use_split_map: boolean;
  config: CanonicalDoclingConfig;
  threshold: number;
};

type Profile = 'default' | 'simple' | 'aggressive';
type Pipeline = 'standard' | 'vlm' | 'asr';
type PdfBackend = 'dlparse_v4' | 'pypdfium2' | 'dlparse_v1' | 'dlparse_v2';
type TableMode = 'fast' | 'accurate';

export const CCDocumentIntelligence: React.FC = () => {
  const { fileId } = useParams<{ fileId: string }>();

  const validFileId = useMemo(() => fileId || '', [fileId]);
  const { accessToken } = useAuth();
  const [page, setPage] = useState<number>(1);
  const [outlineOptions, setOutlineOptions] = useState<Array<{ id: string; title: string; start_page: number; end_page: number }>>([]);
  const [profile, setProfile] = useState<Profile>('default');
  const [pipeline, setPipeline] = useState<Pipeline>('standard');
  // VLM pipeline config (mutually exclusive options)
  type VlmMode = 'preset' | 'local' | 'api';
  const [vlmMode, setVlmMode] = useState<VlmMode>('preset');
  const [vlmPreset, setVlmPreset] = useState<string>('smoldocling');
  const [vlmLocalJson, setVlmLocalJson] = useState<string>('');
  const [vlmApiJson, setVlmApiJson] = useState<string>('');
  type VlmProvider = 'ollama' | 'openai' | '';
  const [vlmProvider, setVlmProvider] = useState<VlmProvider>('');
  const [vlmProviderModel, setVlmProviderModel] = useState<string>('');
  const [vlmProviderBaseUrl, setVlmProviderBaseUrl] = useState<string>('');
  const [ollamaModels, setOllamaModels] = useState<string[]>([]);
  const [pdfBackend, setPdfBackend] = useState<PdfBackend>('dlparse_v4');
  const [doOCR, setDoOCR] = useState(true);
  const [forceOCR, setForceOCR] = useState(false);
  const [tableMode, setTableMode] = useState<TableMode>('fast');
  const [doPicClass, setDoPicClass] = useState(false);
  const [doPicDesc, setDoPicDesc] = useState(false);
  const [picDescPrompt, setPicDescPrompt] = useState('Describe the image succinctly for study notes.');
  // Picture description config (mutually exclusive local/api)
  type PicDescMode = 'local' | 'api';
  const [picDescMode, setPicDescMode] = useState<PicDescMode>('local');
  const [picDescLocalJson, setPicDescLocalJson] = useState<string>('');
  const [picDescApiJson, setPicDescApiJson] = useState<string>('');
  const [busy, setBusy] = useState(false);
  // Split sections (from split_map)
  const [splitSections, setSplitSections] = useState<Array<{ id: string; title: string; start: number; end: number }>>([]);
  const [selectedSectionId, setSelectedSectionId] = useState<string>('full');
  // Load available canonical bundles
  type Artefact = { id: string; type: string; rel_path: string; extra?: Record<string, unknown>; created_at?: string };
  const [bundles, setBundles] = useState<Artefact[]>([]);
  const [currentBundle, setCurrentBundle] = useState<string>('');
  const [combineSplit, setCombineSplit] = useState<boolean>(false);
  // Batch selection (group of split bundles or single bundle)
  type BundleGroup = { key: string; label: string; bundleIds: string[]; isGroup: boolean };
  const groupItems = useMemo<BundleGroup[]>(() => {
    if (!bundles.length) return [];
    const byGroup: Record<string, { ids: string[]; meta: { created_at?: string; pipeline?: string; group_pack_type?: string; producer?: string; ocr_mode?: string; processing_mode?: string; bundle_type?: string }[] }> = {};
    const singles: BundleGroup[] = [];
    for (const b of bundles) {
      const ex = (b.extra as Record<string, unknown>) || {};
      const gid = (ex.group_id as string | undefined) || '';
      if (gid) {
        if (!byGroup[gid]) byGroup[gid] = { ids: [], meta: [] };
        byGroup[gid].ids.push(b.id);
        const pipeline = (ex.pipeline as string | undefined) || (b.type === 'docling_vlm' ? 'vlm' : (b.type === 'vlm_section_page_bundle' ? 'vlm-pages' : 'standard'));
        const producer = (ex.producer as string | undefined) || 'manual';
        const do_ocr = ((ex.config as Record<string, unknown>)?.do_ocr as boolean) ?? true;
        const ocrLabel = do_ocr ? 'OCR' : 'no-OCR';
        byGroup[gid].meta.push({ 
          created_at: b.created_at, 
          pipeline, 
          group_pack_type: ex.group_pack_type as string | undefined,
          producer,
          ocr_mode: ocrLabel,
          processing_mode: ex.processing_mode as string | undefined,
          bundle_type: ex.bundle_type as string | undefined
        });
      } else {
        const pipeline = (ex.pipeline as string | undefined) || (b.type === 'docling_vlm' ? 'vlm' : (b.type === 'vlm_section_page_bundle' ? 'vlm-pages' : 'standard'));
        const producer = (ex.producer as string | undefined) || 'manual';
        const producerLabel = producer === 'auto_split' ? 'auto' : 'manual';
        singles.push({ 
          key: `single:${b.id}`, 
          label: `${new Date(b.created_at || '').toLocaleString()} • ${pipeline} • ${producerLabel}`, 
          bundleIds: [b.id], 
          isGroup: false 
        });
      }
    }
    const groups: BundleGroup[] = Object.entries(byGroup)
      .map(([gid, v]) => {
        const newest = v.meta.sort((a,b)=> new Date(b.created_at || 0).getTime() - new Date(a.created_at || 0).getTime())[0];
        const producerLabel = newest.producer === 'auto_split' ? 'auto' : 'manual';
        // Determine pack type - use processing_mode as fallback for better detection
        let packType = newest.group_pack_type;
        if (!packType) {
          // Smart fallback based on bundle characteristics
          if (newest.processing_mode === 'whole_document' || newest.bundle_type === 'docling_bundle') {
            packType = 'whole';
          } else if (v.ids.length === 1) {
            packType = 'single';
          } else {
            packType = 'split';
          }
        }
        const ocrInfo = v.meta.length > 0 ? `${newest.ocr_mode || 'mixed'}` : '';
        const label = `${new Date(newest.created_at || '').toLocaleString()} • ${packType} • ${newest.pipeline || 'standard'} • ${ocrInfo} • ${v.ids.length} parts • ${producerLabel}`;
        return { key: `group:${gid}`, label, bundleIds: v.ids, isGroup: v.ids.length > 1 };
      })
      .sort((a,b)=> new Date(byGroup[b.key.split(':')[1]]?.meta[0]?.created_at || 0).getTime() - new Date(byGroup[a.key.split(':')[1]]?.meta[0]?.created_at || 0).getTime());
    return [...groups, ...singles];
  }, [bundles]);
  const [selectedGroupKey, setSelectedGroupKey] = useState<string>('');

  useEffect(() => {
    const loadBundles = async () => {
      if (!validFileId) return;
      const API_BASE = import.meta.env.VITE_API_BASE || (location.port.startsWith('517') ? 'http://127.0.0.1:8080' : '/api');
      const token = accessToken || '';
      const res = await fetch(`${API_BASE}/database/files/${encodeURIComponent(validFileId)}/artefacts`, { headers: { Authorization: `Bearer ${token}` } });
      if (!res.ok) return;
      const arts: Artefact[] = await res.json();
      const list = arts.filter(a => a.type === 'docling_standard' || a.type === 'docling_vlm' || a.type === 'vlm_section_page_bundle' || a.type === 'docling_bundle' || a.type === 'docling_bundle_split' || a.type === 'docling_bundle_split_pages' || a.type === 'canonical_docling_json')
        .sort((a, b) => {
          // Sort by creation time, newest first
          const ta = new Date(a.created_at || 0).getTime();
          const tb = new Date(b.created_at || 0).getTime();
          return tb - ta;
        });
      setBundles(list);
      
      // Initialize currentBundle if not set
      if (list.length && !currentBundle) {
        setCurrentBundle(list[0].id);
      }
      
      // Initialize selected group key to latest group or single
      const gi = (() => {
        const arr = list;
        const withGroup = arr.filter(a => ((a.extra as Record<string, unknown>)||{}).group_id);
        if (withGroup.length) {
          const gid = ((withGroup[0].extra as Record<string, unknown>).group_id as string);
          return `group:${gid}`;
        }
        return `single:${arr[0]?.id || ''}`;
      })();
      if (!selectedGroupKey && gi) {
        setSelectedGroupKey(gi);
      }
    };
    loadBundles();
  }, [validFileId]); // Remove circular dependencies to prevent timing issues
  // eslint-disable-next-line react-hooks/exhaustive-deps
  
  // Separate effect to handle initialization after bundles are loaded
  useEffect(() => {
    if (bundles.length > 0 && !currentBundle) {
      setCurrentBundle(bundles[0].id);
    }
  }, [bundles, currentBundle]);
  
  // Separate effect to sync selectedGroupKey with currentBundle
  useEffect(() => {
    if (bundles.length > 0 && currentBundle && !selectedGroupKey) {
      const bundle = bundles.find(b => b.id === currentBundle);
      if (bundle) {
        const extra = bundle.extra as Record<string, unknown> || {};
        const groupId = extra.group_id as string;
        if (groupId) {
          setSelectedGroupKey(`group:${groupId}`);
        } else {
          setSelectedGroupKey(`single:${currentBundle}`);
        }
      }
    }
  }, [bundles, currentBundle, selectedGroupKey]);
  
  const [splitThreshold] = useState<number>(50);
  const autoSplit = useMemo(() => {
    const pages = splitSections.reduce((m, s) => Math.max(m, s.end), 0);
    return pages >= splitThreshold && splitSections.length > 0;
  }, [splitSections, splitThreshold]);
  const [doFormula, setDoFormula] = useState(false);
  const [doCode, setDoCode] = useState(false);
  const [tableCellMatching, setTableCellMatching] = useState<boolean>(false);

  // Outputs are fixed to all formats for canonical bundles

  useEffect(() => {
    const run = async () => {
      if (!validFileId) return;
      setOutlineOptions([]);
      const API_BASE = import.meta.env.VITE_API_BASE || (location.port.startsWith('517') ? 'http://127.0.0.1:8080' : '/api');
      try {
        const artsRes = await fetch(`${API_BASE}/database/files/${encodeURIComponent(validFileId)}/artefacts`, {
          headers: { 'Authorization': `Bearer ${accessToken || ''}` }
        });
        if (!artsRes.ok) return;
        const arts: Array<{ id: string; type: string; rel_path?: string }> = await artsRes.json();
        const outlineArt = arts.find(a => a.type === 'document_outline_hierarchy');
        if (!outlineArt) return;
        const jsonRes = await fetch(`${API_BASE}/database/files/${encodeURIComponent(validFileId)}/artefacts/${encodeURIComponent(outlineArt.id)}/json`, {
          headers: { 'Authorization': `Bearer ${accessToken || ''}` }
        });
        if (!jsonRes.ok) return;
        const doc = await jsonRes.json();
        const sections = (doc.sections || []) as Array<{ id: string; title: string; start_page: number; end_page: number }>;
        setOutlineOptions(sections.map(s => ({ id: s.id, title: s.title, start_page: s.start_page, end_page: s.end_page })));
        // Load split map
        const splitArt = arts.find(a => a.type === 'split_map_json');
        if (splitArt) {
          const smRes = await fetch(`${API_BASE}/database/files/${encodeURIComponent(validFileId)}/artefacts/${encodeURIComponent(splitArt.id)}/json`, {
            headers: { 'Authorization': `Bearer ${accessToken || ''}` }
          });
          if (smRes.ok) {
            const sm = await smRes.json();
            const entries = Array.isArray(sm.entries) ? sm.entries : [];
            const secs = (entries as Array<Record<string, unknown>>)
              .map((e) => ({
                id: String((e.id as string) || `${e.start_page as number}-${e.end_page as number}`),
                title: String((e.title as string) || ''),
                start: Number((e.start_page as number) || 1),
                end: Number((e.end_page as number) || 1)
              }))
              .filter((e) => Number.isFinite(e.start) && Number.isFinite(e.end));
            setSplitSections(secs);
          }
        }
      } catch {
        // ignore
      }
    };
    run();
  }, [validFileId]);

  return (
    <Box sx={{ width: '100%', height: '100%', display: 'flex', overflow: 'hidden' }}>
      <Box sx={{ width: 320, height: '100%', borderRight: '1px solid var(--color-divider)', overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
        <Box sx={{ flex: 1, minHeight: 0 }}>
          <CCEnhancedFilePanel 
            fileId={validFileId} 
            selectedPage={page} 
            onSelectPage={setPage}
            currentSection={(function(){
              const s = [...outlineOptions].sort((a,b)=>a.start_page-b.start_page).find(x => page >= x.start_page && page <= x.end_page);
              return s ? { start: s.start_page, end: s.end_page } : undefined;
            })()}
          />
        </Box>
      </Box>
      <Box sx={{ flex: 1, height: '100%', position: 'relative', display: 'flex', flexDirection: 'row' }}>
        <Box sx={{ flex: 1, minWidth: 0, borderRight: '1px solid var(--color-divider)', display: 'flex', flexDirection: 'column' }}>
          <CCDoclingViewer
            fileId={validFileId}
            currentPage={page}
            onPageChange={setPage}
            hideToolbar
            sectionRange={(function(){
              const s = [...outlineOptions].sort((a,b)=>a.start_page-b.start_page).find(x => page >= x.start_page && page <= x.end_page);
              return s ? { start: s.start_page, end: s.end_page } : undefined;
            })()}
          />
        </Box>
        <Box sx={{ width: '42%', minWidth: 320, display: 'flex', flexDirection: 'column' }}>
          <CCBundleViewer
            fileId={validFileId}
            bundleId={!combineSplit ? currentBundle : undefined}
            currentPage={page}
            combinedBundles={combineSplit ? (function(){
              const grp = groupItems.find(g => g.key === selectedGroupKey);
              if (!grp) return [];
              // Order split parts by split_order if present
              const inGroup = bundles.filter(b => grp.bundleIds.includes(b.id));
              const ordered = inGroup.sort((a,b) => {
                const ao = Number(((a.extra as Record<string, unknown>)||{}).split_order) || 0;
                const bo = Number(((b.extra as Record<string, unknown>)||{}).split_order) || 0;
                return ao - bo;
              });
              return ordered.map(b => ({ id: b.id }));
            })() : undefined}
          />
        </Box>
      </Box>
      <Box sx={{ width: 360, height: '100%', borderLeft: '1px solid var(--color-divider)', display: 'flex', flexDirection: 'column' }}>
        <Box sx={{ p: 2, fontWeight: 600 }}>AI Document Intelligence</Box>
        <Divider />
        <Box sx={{ p: 2, overflow: 'auto', display: 'flex', flexDirection: 'column', gap: 1 }}>
          <Typography variant="body2" sx={{ color: 'var(--color-text-2)', fontWeight: 600 }}>Canonical Docling</Typography>
          {bundles.length > 0 && (
            <>
              <Typography variant="body2" sx={{ color: 'var(--color-text-2)' }}>Existing bundles</Typography>
              {/* Batch selector (groups and singles) */}
              <Select size="small" value={selectedGroupKey} onChange={(e: SelectChangeEvent<string>) => {
                const key = e.target.value as string;
                setSelectedGroupKey(key);
                const grp = groupItems.find(g => g.key === key);
                if (grp && grp.bundleIds.length) setCurrentBundle(grp.bundleIds[0]);
                setCombineSplit(Boolean(grp && grp.isGroup));
              }}>
                {groupItems.map(g => (
                  <MenuItem key={g.key} value={g.key}>{g.label}</MenuItem>
                ))}
              </Select>
              {/* Only show combine toggle if multi-bundle group selected */}
              {(() => {
                const grp = groupItems.find(g => g.key === selectedGroupKey);
                return grp && grp.isGroup ? (
                  <FormControlLabel control={<Switch checked={combineSplit} onChange={(e) => setCombineSplit(e.target.checked)} />} label="Combine split bundles" />
                ) : null;
              })()}
              {/* When not combining, allow selecting a single bundle within selected group */}
              {!combineSplit && (() => {
                const grp = groupItems.find(g => g.key === selectedGroupKey);
                return grp && grp.isGroup; // Only show for groups with multiple bundles
              })() && (
              <Select size="small" value={currentBundle} onChange={(e) => setCurrentBundle(e.target.value as string)}>
                {bundles.filter(b => {
                  const grp = groupItems.find(g => g.key === selectedGroupKey);
                  return grp ? grp.bundleIds.includes(b.id) : true;
                }).sort((a,b) => {
                  const ao = Number(((a.extra as Record<string, unknown>)||{}).split_order) || 0;
                  const bo = Number(((b.extra as Record<string, unknown>)||{}).split_order) || 0;
                  return ao - bo;
                }).map(b => {
                  const ex = (b.extra as Record<string, unknown>) || {};
                  const splitOrder = Number(ex.split_order ?? NaN);
                  const heading = ex.split_heading as string | undefined;
                  const pipeline = (ex.pipeline as string) || (b.type === 'docling_vlm' ? 'vlm' : 'standard');
                  const base = heading ? `${heading}${Number.isFinite(splitOrder) ? ` (#${splitOrder})` : ''}` : (new Date(b.created_at || '').toLocaleString() || b.id);
                  return (<MenuItem key={b.id} value={b.id}>{`${base} [${pipeline}]`}</MenuItem>);
                })}
              </Select>
              )}
            </>
          )}
          <Select size="small" value={profile} onChange={(e: SelectChangeEvent<Profile>) => setProfile(e.target.value as Profile)}>
            <MenuItem value="default">Default</MenuItem>
            <MenuItem value="simple">Simple</MenuItem>
            <MenuItem value="aggressive">Aggressive</MenuItem>
          </Select>
          <Typography variant="body2" sx={{ color: 'var(--color-text-2)' }}>Pipeline</Typography>
          <Select size="small" value={pipeline} onChange={(e: SelectChangeEvent<Pipeline>) => setPipeline(e.target.value as Pipeline)}>
            <MenuItem value="standard">Standard</MenuItem>
            <MenuItem value="vlm">VLM</MenuItem>
            <MenuItem value="asr">ASR</MenuItem>
          </Select>
          {pipeline === 'vlm' && (
            <>
              <Typography variant="body2" sx={{ color: 'var(--color-text-2)' }}>VLM configuration</Typography>
              <Select size="small" value={vlmMode} onChange={(e: SelectChangeEvent<VlmMode>) => setVlmMode(e.target.value as VlmMode)}>
                <MenuItem value="preset">Preset</MenuItem>
                <MenuItem value="local">Local (JSON)</MenuItem>
                <MenuItem value="api">API (JSON)</MenuItem>
              </Select>
              {vlmMode === 'preset' && (
                <Select size="small" value={vlmPreset} onChange={(e) => setVlmPreset(e.target.value as string)}>
                  <MenuItem value="smoldocling">smoldocling</MenuItem>
                  <MenuItem value="smoldocling_vllm">smoldocling_vllm</MenuItem>
                  <MenuItem value="granite_vision">granite_vision</MenuItem>
                  <MenuItem value="granite_vision_vllm">granite_vision_vllm</MenuItem>
                  <MenuItem value="granite_vision_ollama">granite_vision_ollama</MenuItem>
                  <MenuItem value="got_ocr_2">got_ocr_2</MenuItem>
                </Select>
              )}
              {vlmMode === 'local' && (
                <TextField size="small" label="VLM Local JSON" placeholder='{"repo_id":"..."}' value={vlmLocalJson} onChange={(e: React.ChangeEvent<HTMLInputElement>) => setVlmLocalJson(e.target.value)} multiline minRows={2} />
              )}
              {vlmMode === 'api' && (
                <>
                  <Select size="small" value={vlmProvider} onChange={(e: SelectChangeEvent<VlmProvider>) => setVlmProvider(e.target.value as VlmProvider)}>
                    <MenuItem value="">Custom JSON</MenuItem>
                    <MenuItem value="ollama">Ollama</MenuItem>
                    <MenuItem value="openai">OpenAI</MenuItem>
                  </Select>
                  {vlmProvider === 'ollama' && (
                    <>
                      <TextField size="small" label="Ollama Base URL" placeholder="http://localhost:11434" value={vlmProviderBaseUrl} onChange={(e: React.ChangeEvent<HTMLInputElement>) => setVlmProviderBaseUrl(e.target.value)} />
                      <Select size="small" value={vlmProviderModel} onOpen={async () => {
                        try {
                          const base = vlmProviderBaseUrl || (import.meta.env.VITE_OLLAMA_BASE_URL || 'http://localhost:11434');
                          const resp = await fetch(`${base.replace(/\/$/, '')}/api/tags`);
                          if (resp.ok) {
                            const data = await resp.json();
                            const models = Array.isArray(data.models) ? (data.models as Array<{ model?: string; name?: string }>).map((m) => m.model || m.name || '').filter(Boolean) : [];
                            setOllamaModels(models);
                          }
                        } catch (_e) { /* no-op */ }
                      }} onChange={(e) => setVlmProviderModel(e.target.value as string)}>
                        {ollamaModels.map(m => (<MenuItem key={m} value={m}>{m}</MenuItem>))}
                      </Select>
                    </>
                  )}
                  {vlmProvider === 'openai' && (
                    <>
                      <TextField size="small" label="OpenAI Base URL (optional)" placeholder="https://api.openai.com/v1" value={vlmProviderBaseUrl} onChange={(e: React.ChangeEvent<HTMLInputElement>) => setVlmProviderBaseUrl(e.target.value)} />
                      <Select size="small" value={vlmProviderModel} onChange={(e) => setVlmProviderModel(e.target.value as string)}>
                        <MenuItem value="gpt-4o-mini">gpt-4o-mini</MenuItem>
                        <MenuItem value="gpt-4o">gpt-4o</MenuItem>
                        <MenuItem value="gpt-4.1-mini">gpt-4.1-mini</MenuItem>
                      </Select>
                    </>
                  )}
                  {vlmProvider === '' && (
                    <TextField size="small" label="VLM API JSON" placeholder='{"provider":"ollama","base_url":"http://...","model":"..."}' value={vlmApiJson} onChange={(e: React.ChangeEvent<HTMLInputElement>) => setVlmApiJson(e.target.value)} multiline minRows={2} />
                  )}
                </>
              )}
            </>
          )}
          <Typography variant="body2" sx={{ color: 'var(--color-text-2)' }}>PDF Backend</Typography>
          <Select size="small" value={pdfBackend} onChange={(e: SelectChangeEvent<PdfBackend>) => setPdfBackend(e.target.value as PdfBackend)}>
            <MenuItem value="dlparse_v4">dlparse_v4 (default)</MenuItem>
            <MenuItem value="pypdfium2">pypdfium2</MenuItem>
            <MenuItem value="dlparse_v1">dlparse_v1</MenuItem>
            <MenuItem value="dlparse_v2">dlparse_v2</MenuItem>
          </Select>
          <FormControlLabel control={<Switch checked={doOCR} onChange={(e) => setDoOCR(e.target.checked)} />} label="OCR" />
          <FormControlLabel control={<Switch checked={forceOCR} onChange={(e) => setForceOCR(e.target.checked)} />} label="Force OCR" />
          <Typography variant="body2" sx={{ color: 'var(--color-text-2)' }}>Table Mode</Typography>
          <Select size="small" value={tableMode} onChange={(e: SelectChangeEvent<TableMode>) => setTableMode(e.target.value as TableMode)}>
            <MenuItem value="fast">Fast</MenuItem>
            <MenuItem value="accurate">Accurate</MenuItem>
          </Select>
          <Typography variant="body2" sx={{ color: 'var(--color-text-2)' }}>Section</Typography>
          <Select size="small" value={selectedSectionId} onChange={(e: SelectChangeEvent<string>) => setSelectedSectionId(e.target.value as string)}>
            <MenuItem value="full">{autoSplit ? 'Full document (auto split)' : 'Full document'}</MenuItem>
            {splitSections.map(sec => (
              <MenuItem key={sec.id} value={sec.id}>{sec.title ? `${sec.title} (${sec.start}-${sec.end})` : `Pages ${sec.start}-${sec.end}`}</MenuItem>
            ))}
          </Select>
          <FormControlLabel control={<Switch checked={doPicClass} onChange={(e) => setDoPicClass(e.target.checked)} />} label="Picture classification" />
          <FormControlLabel control={<Switch checked={doPicDesc} onChange={(e) => setDoPicDesc(e.target.checked)} />} label="Picture description" />
          {doPicDesc && (
            <>
              <TextField size="small" label="Description prompt" value={picDescPrompt} onChange={(e: React.ChangeEvent<HTMLInputElement>) => setPicDescPrompt(e.target.value)} />
              <Typography variant="body2" sx={{ color: 'var(--color-text-2)' }}>Picture description configuration</Typography>
              <Select size="small" value={picDescMode} onChange={(e: SelectChangeEvent<PicDescMode>) => setPicDescMode(e.target.value as PicDescMode)}>
                <MenuItem value="local">Local (JSON)</MenuItem>
                <MenuItem value="api">API (JSON)</MenuItem>
              </Select>
              {picDescMode === 'local' && (
                <TextField size="small" label="Picture Description Local JSON" placeholder='{"repo_id":"..."}' value={picDescLocalJson} onChange={(e: React.ChangeEvent<HTMLInputElement>) => setPicDescLocalJson(e.target.value)} multiline minRows={2} />
              )}
              {picDescMode === 'api' && (
                <TextField size="small" label="Picture Description API JSON" placeholder='{"base_url":"..."}' value={picDescApiJson} onChange={(e: React.ChangeEvent<HTMLInputElement>) => setPicDescApiJson(e.target.value)} multiline minRows={2} />
              )}
            </>
          )}
          <FormControlLabel control={<Switch checked={doFormula} onChange={(e) => setDoFormula(e.target.checked)} />} label="Formula enrichment" />
          <FormControlLabel control={<Switch checked={doCode} onChange={(e) => setDoCode(e.target.checked)} />} label="Code enrichment" />
          <FormControlLabel control={<Switch checked={tableCellMatching} onChange={(e) => setTableCellMatching(e.target.checked)} />} label="Table cell matching" />
          {/* Outputs are always all formats for canonical bundles; UI omitted */}
          <Button variant="contained" disabled={busy || !validFileId} onClick={async () => {
            try {
              setBusy(true);
              const API_BASE = import.meta.env.VITE_API_BASE || (location.port.startsWith('517') ? 'http://127.0.0.1:8080' : '/api');
              const token = accessToken || '';
              const body: CanonicalDoclingRequest = {
                use_split_map: selectedSectionId === 'full' ? autoSplit : false,
                config: {
                  pipeline,
                  pdf_backend: pdfBackend,
                  do_ocr: doOCR,
                  force_ocr: forceOCR,
                  table_mode: tableMode,
                  do_picture_classification: doPicClass,
                  do_picture_description: doPicDesc,
                  picture_description_prompt: doPicDesc ? picDescPrompt : undefined,
                  target_type: 'zip',
                  image_export_mode: 'referenced',
                  table_cell_matching: tableCellMatching
                },
                threshold: splitThreshold
              };
              body.config.to_formats = ['json','html','text','md','doctags'];
              body.config.do_formula_enrichment = doFormula;
              body.config.do_code_enrichment = doCode;
              // Apply selected section as custom range
              const sel = selectedSectionId !== 'full' ? splitSections.find(s => s.id === selectedSectionId) : undefined;
              if (sel) {
                (body as unknown as { custom_range: [number, number]; custom_label: string; selected_section_id: string; selected_section_title: string }).custom_range = [sel.start, sel.end];
                (body as unknown as { custom_range: [number, number]; custom_label: string; selected_section_id: string; selected_section_title: string }).custom_label = sel.title || `Pages ${sel.start}-${sel.end}`;
                (body as unknown as { custom_range: [number, number]; custom_label: string; selected_section_id: string; selected_section_title: string }).selected_section_id = sel.id;
                (body as unknown as { custom_range: [number, number]; custom_label: string; selected_section_id: string; selected_section_title: string }).selected_section_title = sel.title || '';
              }
              // If full and autoSplit, ensure threshold present
              if (selectedSectionId === 'full' && autoSplit) {
                (body as unknown as { threshold: number }).threshold = splitThreshold;
              }
              // Picture description mutually exclusive config
              if (doPicDesc) {
                if (picDescMode === 'local' && picDescLocalJson.trim()) {
                  body.config.picture_description_local = picDescLocalJson.trim();
                  body.config.picture_description_api = undefined;
                } else if (picDescMode === 'api' && picDescApiJson.trim()) {
                  body.config.picture_description_api = picDescApiJson.trim();
                  body.config.picture_description_local = undefined;
                } else {
                  body.config.picture_description_local = undefined;
                  body.config.picture_description_api = undefined;
                }
              } else {
                body.config.picture_description_local = undefined;
                body.config.picture_description_api = undefined;
              }
              // VLM mutually exclusive config + provider presets
              if (pipeline === 'vlm') {
                if (vlmMode === 'preset') {
                  body.config.vlm_pipeline_model = vlmPreset;
                  body.config.vlm_pipeline_model_local = undefined;
                  body.config.vlm_pipeline_model_api = undefined;
                } else if (vlmMode === 'local' && vlmLocalJson.trim()) {
                  body.config.vlm_pipeline_model_local = vlmLocalJson.trim();
                  body.config.vlm_pipeline_model = undefined;
                  body.config.vlm_pipeline_model_api = undefined;
                } else if (vlmMode === 'api') {
                  if (vlmProvider) {
                    (body.config as unknown as { vlm_provider: string; vlm_provider_model: string; vlm_provider_base_url: string }).vlm_provider = vlmProvider;
                    (body.config as unknown as { vlm_provider: string; vlm_provider_model: string; vlm_provider_base_url: string }).vlm_provider_model = vlmProviderModel.trim();
                    (body.config as unknown as { vlm_provider: string; vlm_provider_model: string; vlm_provider_base_url: string }).vlm_provider_base_url = vlmProviderBaseUrl.trim();
                    body.config.vlm_pipeline_model_api = undefined;
                    body.config.vlm_pipeline_model = undefined;
                    body.config.vlm_pipeline_model_local = undefined;
                  } else if (vlmApiJson.trim()) {
                    body.config.vlm_pipeline_model_api = vlmApiJson.trim();
                    body.config.vlm_pipeline_model = undefined;
                    body.config.vlm_pipeline_model_local = undefined;
                  } else {
                    body.config.vlm_pipeline_model = undefined;
                    body.config.vlm_pipeline_model_local = undefined;
                    body.config.vlm_pipeline_model_api = undefined;
                  }
                }
              } else {
                body.config.vlm_pipeline_model = undefined;
                body.config.vlm_pipeline_model_local = undefined;
                body.config.vlm_pipeline_model_api = undefined;
              }
              const resp = await fetch(`${API_BASE}/database/files/${encodeURIComponent(validFileId)}/artefacts/canonical-docling`, {
                method: 'POST',
                headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
                body: JSON.stringify(body)
              });
              const data = await resp.json();
              console.log('canonical-docling:', data);
              // Refresh bundles list
              try {
                const res = await fetch(`${API_BASE}/database/files/${encodeURIComponent(validFileId)}/artefacts`, { headers: { Authorization: `Bearer ${token}` } });
                if (res.ok) {
                  const arts: Artefact[] = await res.json();
                  const list = arts.filter(a => a.type === 'docling_standard' || a.type === 'docling_vlm' || a.type === 'vlm_section_page_bundle' || a.type === 'docling_bundle' || a.type === 'docling_bundle_split' || a.type === 'docling_bundle_split_pages' || a.type === 'canonical_docling_json')
                    .sort((a, b) => {
                      // Sort by creation time, newest first
                      const ta = new Date(a.created_at || 0).getTime();
                      const tb = new Date(b.created_at || 0).getTime();
                      return tb - ta;
                    });
                  setBundles(list);
                  if (list.length && !currentBundle) setCurrentBundle(list[0].id);
                }
              } catch (_err: unknown) { void 0; }
            } finally {
              setBusy(false);
            }
          }}>Generate Doclings</Button>
        </Box>
      </Box>
    </Box>
  );
};

export default CCDocumentIntelligence;

