import { Fragment, lazy, Suspense, useMemo, useRef, useState, type ChangeEvent } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { ArrowLeft, Upload, GitBranch, Download, FileImage, Eye, Layers, FolderInput, Settings, ListChecks } from 'lucide-react';
import { toast } from 'sonner';

import {
  Badge,
  Button,
  Card,
  CardContent,
  CardHeader,
  CardTitle,
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
  getDataset,
  listDatasetFiles,
  listDatasetVersions,
  uploadDatasetFiles,
  createDatasetVersion,
  fileDownloadUrl,
  isViewableImagingFile,
  fetchAsFile,
  VISIBILITY_LABEL,
  formatBytes,
  type ImagehubFile,
} from '@ump/shared';
import { SegmentationUploadDialog } from '../components/SegmentationUploadDialog';
import { UploadDataDialog } from '../features/data-import/presentation/components/UploadDataDialog';

// Lazy so @kitware/vtk.js loads only when a viewer actually opens — keeps it out
// of the dataset page's initial bundle (it lands in its own async chunk).
const DatasetFileViewerDialog = lazy(() => import('../components/DatasetFileViewerDialog'));

/** Human-readable imaging summary from the best-effort sniff metadata. */
function modalityOf(meta: Record<string, unknown>): string {
  if (!meta || typeof meta !== 'object') return '';
  const fmt = meta.format;
  if (fmt === 'dicom') {
    const mod = meta.modality ? String(meta.modality) : '';
    const dim = meta.rows && meta.columns ? `${String(meta.rows)}×${String(meta.columns)}` : '';
    return [mod, dim].filter(Boolean).join(' · ');
  }
  if (fmt === 'nifti' && Array.isArray(meta.shape)) {
    return `NIfTI ${(meta.shape as unknown[]).map(String).join('×')}`;
  }
  return '';
}

export function DatasetDetailPage() {
  const { id = '' } = useParams();
  const navigate = useNavigate();
  const qc = useQueryClient();
  const fileInput = useRef<HTMLInputElement>(null);
  const [viewer, setViewer] = useState<
    { file: File; name: string; masks: { id: string; organLabel: string; logicalPath: string }[] } | null
  >(null);
  const [viewerLoadingId, setViewerLoadingId] = useState<string | null>(null);
  const [segTarget, setSegTarget] = useState<ImagehubFile | null>(null);
  const [importOpen, setImportOpen] = useState(false);

  const dsQ = useQuery({ queryKey: ['imagehub', 'dataset', id], queryFn: () => getDataset(id), enabled: !!id });
  const filesQ = useQuery({
    queryKey: ['imagehub', 'dataset', id, 'files'],
    queryFn: () => listDatasetFiles(id),
    enabled: !!id,
  });
  const versionsQ = useQuery({
    queryKey: ['imagehub', 'dataset', id, 'versions'],
    queryFn: () => listDatasetVersions(id),
    enabled: !!id,
  });

  const invalidate = () => qc.invalidateQueries({ queryKey: ['imagehub', 'dataset', id] });

  const uploadMut = useMutation({
    mutationFn: (files: File[]) => uploadDatasetFiles(id, files),
    onSuccess: (res) => {
      const dups = res.files.filter((f) => f.deduped).length;
      toast.success(
        `Đã tải lên ${res.files.length} tệp${dups ? ` (${dups} trùng nội dung, đã khử trùng lặp)` : ''}`,
      );
      invalidate();
    },
    onError: () => toast.error('Tải tệp thất bại'),
  });

  const versionMut = useMutation({
    mutationFn: () => createDatasetVersion(id),
    onSuccess: (v) => {
      toast.success(`Đã tạo phiên bản v${v.seq}`);
      invalidate();
    },
    onError: () => toast.error('Không tạo được phiên bản'),
  });

  const onPick = (e: ChangeEvent<HTMLInputElement>) => {
    const files = Array.from(e.target.files ?? []);
    if (files.length) uploadMut.mutate(files);
    e.target.value = '';
  };

  const download = async (f: ImagehubFile) => {
    try {
      const { url } = await fileDownloadUrl(id, f.id);
      window.open(url, '_blank', 'noopener');
    } catch {
      toast.error('Không lấy được liên kết tải');
    }
  };

  /** Resolve a presigned URL, fetch the bytes as a File, and open the 3D viewer. */
  const openViewer = async (f: ImagehubFile) => {
    setViewerLoadingId(f.id);
    try {
      const { url } = await fileDownloadUrl(id, f.id);
      const file = await fetchAsFile(url, f.logicalPath);
      // The organ masks linked to this image become the viewer's selectable overlays.
      const masks = (filesQ.data ?? [])
        .filter((m) => m.fileKind === 'segmentation' && m.parentFileId === f.id)
        .map((m) => ({ id: m.id, organLabel: m.organLabel || m.logicalPath, logicalPath: m.logicalPath }));
      setViewer({ file, name: f.logicalPath, masks });
    } catch {
      toast.error('Không mở được trình xem ảnh');
    } finally {
      setViewerLoadingId(null);
    }
  };

  const ds = dsQ.data;
  const files = filesQ.data ?? [];
  const versions = versionsQ.data ?? [];

  // Group segmentation masks under the image they segment; only image rows render at top level.
  const masksByParent = useMemo(() => {
    const m = new Map<string, ImagehubFile[]>();
    for (const f of files) {
      if (f.fileKind === 'segmentation' && f.parentFileId) {
        const arr = m.get(f.parentFileId);
        if (arr) arr.push(f);
        else m.set(f.parentFileId, [f]);
      }
    }
    return m;
  }, [files]);
  const imageRows = files.filter((f) => f.fileKind !== 'segmentation');

  return (
    <div className="mx-auto max-w-5xl space-y-6">
      <Button variant="ghost" size="sm" onClick={() => navigate('/dashboard')}>
        <ArrowLeft className="mr-2 h-4 w-4" /> Bộ dữ liệu của tôi
      </Button>

      {dsQ.isLoading && <p className="text-sm text-muted-foreground">Đang tải…</p>}
      {dsQ.isError && <p className="text-sm text-destructive">Không tải được bộ dữ liệu.</p>}

      {ds && (
        <>
          <div className="flex flex-wrap items-start justify-between gap-3">
            <div>
              <div className="flex items-center gap-2">
                <h1 className="font-serif text-2xl font-semibold text-foreground">{ds.name}</h1>
                <Badge variant="outline">{VISIBILITY_LABEL[ds.visibility]}</Badge>
              </div>
              {ds.description && <p className="mt-1 text-sm text-muted-foreground">{ds.description}</p>}
              {ds.modalityTags.length > 0 && (
                <div className="mt-1 flex flex-wrap gap-1">
                  {ds.modalityTags.map((t) => (
                    <Badge key={t} variant="secondary" className="text-[11px]">
                      {t}
                    </Badge>
                  ))}
                </div>
              )}
            </div>
            <div className="flex gap-2">
              <input ref={fileInput} type="file" multiple className="hidden" onChange={onPick} />
              <Button
                variant="outline"
                onClick={() => fileInput.current?.click()}
                disabled={uploadMut.isPending}
              >
                <Upload className="mr-2 h-4 w-4" /> {uploadMut.isPending ? 'Đang tải…' : 'Tải tệp lên'}
              </Button>
              <Button variant="outline" onClick={() => setImportOpen(true)}>
                <FolderInput className="mr-2 h-4 w-4" /> Nhập dữ liệu
              </Button>
              <Button variant="outline" onClick={() => navigate(`/dashboard/datasets/${id}/tasks`)}>
                <ListChecks className="mr-2 h-4 w-4" /> Công việc
              </Button>
              <Button
                onClick={() => versionMut.mutate()}
                disabled={versionMut.isPending || files.length === 0}
              >
                <GitBranch className="mr-2 h-4 w-4" /> Tạo phiên bản
              </Button>
              <Button
                variant="outline"
                size="icon"
                onClick={() => navigate(`/dashboard/datasets/${id}/settings`)}
                title="Cài đặt"
              >
                <Settings className="h-4 w-4" />
              </Button>
            </div>
          </div>

          <Card>
            <CardHeader>
              <CardTitle className="text-base">Tệp ({files.length})</CardTitle>
            </CardHeader>
            <CardContent>
              {filesQ.isLoading ? (
                <p className="py-6 text-center text-sm text-muted-foreground">Đang tải…</p>
              ) : files.length === 0 ? (
                <p className="py-6 text-center text-sm text-muted-foreground">
                  Chưa có tệp nào. Bấm “Tải tệp lên” để thêm dữ liệu hình ảnh.
                </p>
              ) : (
                <Table>
                  <TableHeader>
                    <TableRow>
                      <TableHead>Tên tệp</TableHead>
                      <TableHead>Hình ảnh</TableHead>
                      <TableHead className="text-right">Kích thước</TableHead>
                      <TableHead className="w-24" />
                    </TableRow>
                  </TableHeader>
                  <TableBody>
                    {imageRows.map((f) => {
                      const masks = masksByParent.get(f.id) ?? [];
                      const viewable = isViewableImagingFile(f.logicalPath);
                      return (
                        <Fragment key={f.id}>
                          <TableRow>
                            <TableCell className="font-medium">
                              <span className="flex items-center gap-2">
                                <FileImage className="h-4 w-4 shrink-0 text-muted-foreground" />
                                {f.logicalPath}
                              </span>
                            </TableCell>
                            <TableCell className="text-muted-foreground">
                              {modalityOf(f.imagingMeta) || '—'}
                            </TableCell>
                            <TableCell className="text-right text-muted-foreground">
                              {formatBytes(f.size)}
                            </TableCell>
                            <TableCell>
                              <div className="flex items-center justify-end gap-1">
                                {viewable && (
                                  <Button
                                    variant="ghost"
                                    size="icon"
                                    onClick={() => openViewer(f)}
                                    disabled={viewerLoadingId === f.id}
                                    title="Xem ảnh 3D"
                                  >
                                    <Eye className="h-4 w-4" />
                                  </Button>
                                )}
                                {viewable && (
                                  <Button
                                    variant="ghost"
                                    size="icon"
                                    onClick={() => setSegTarget(f)}
                                    title="Gắn mặt nạ phân vùng"
                                  >
                                    <Layers className="h-4 w-4" />
                                  </Button>
                                )}
                                <Button variant="ghost" size="icon" onClick={() => download(f)} title="Tải xuống">
                                  <Download className="h-4 w-4" />
                                </Button>
                              </div>
                            </TableCell>
                          </TableRow>
                          {masks.map((mk) => (
                            <TableRow key={mk.id} className="bg-muted/20">
                              <TableCell className="font-medium">
                                <span className="flex items-center gap-2 pl-6">
                                  <Layers className="h-4 w-4 shrink-0 text-muted-foreground" />
                                  <span className="text-muted-foreground">{mk.organLabel || mk.logicalPath}</span>
                                </span>
                              </TableCell>
                              <TableCell className="text-xs text-muted-foreground">Mặt nạ phân vùng</TableCell>
                              <TableCell className="text-right text-muted-foreground">
                                {formatBytes(mk.size)}
                              </TableCell>
                              <TableCell>
                                <div className="flex items-center justify-end gap-1">
                                  <Button
                                    variant="ghost"
                                    size="icon"
                                    onClick={() => download(mk)}
                                    title="Tải xuống"
                                  >
                                    <Download className="h-4 w-4" />
                                  </Button>
                                </div>
                              </TableCell>
                            </TableRow>
                          ))}
                        </Fragment>
                      );
                    })}
                  </TableBody>
                </Table>
              )}
            </CardContent>
          </Card>

          <Card>
            <CardHeader>
              <CardTitle className="text-base">Phiên bản ({versions.length})</CardTitle>
            </CardHeader>
            <CardContent className="space-y-2">
              {versions.length === 0 ? (
                <p className="py-4 text-center text-sm text-muted-foreground">
                  Chưa có phiên bản nào. Tải tệp rồi bấm “Tạo phiên bản” để chốt một bản chụp (snapshot).
                </p>
              ) : (
                versions.map((v) => (
                  <div
                    key={v.id}
                    className="flex items-center justify-between rounded-md border px-3 py-2 text-sm"
                  >
                    <span className="flex items-center gap-2">
                      <GitBranch className="h-4 w-4 text-muted-foreground" />
                      <strong>v{v.seq}</strong>
                      {v.message && <span className="text-muted-foreground">— {v.message}</span>}
                    </span>
                    <span className="text-muted-foreground">
                      {v.fileCount} tệp
                      {v.createdAt ? ` · ${new Date(v.createdAt).toLocaleString('vi-VN')}` : ''}
                    </span>
                  </div>
                ))
              )}
            </CardContent>
          </Card>
        </>
      )}

      {viewer && (
        <Suspense fallback={null}>
          <DatasetFileViewerDialog
            open
            onOpenChange={(o) => {
              if (!o) setViewer(null);
            }}
            file={viewer.file}
            fileName={viewer.name}
            datasetId={id}
            masks={viewer.masks}
          />
        </Suspense>
      )}

      {segTarget && (
        <SegmentationUploadDialog
          open
          onOpenChange={(o) => {
            if (!o) setSegTarget(null);
          }}
          datasetId={id}
          parentFileId={segTarget.id}
          parentName={segTarget.logicalPath}
          onUploaded={invalidate}
        />
      )}

      {importOpen && (
        <UploadDataDialog open onOpenChange={setImportOpen} datasetId={id} onCompleted={invalidate} />
      )}
    </div>
  );
}
