import { useCoreServices } from '@learnitive/context';
import type { GeneratedResearchArtifact } from '@learnitive/service-core';
import { Button } from '@learnitive/ui-components';
import { getAssetPreviewKind, WsPath } from '@learnitive/ws-path';
import { ExternalLink, Eye, FileInput, FileText, FlaskConical } from 'lucide-react';
import React from 'react';
import { AssetPreview } from './common/asset-preview';

type Props = {
  wsName: string;
  artifact: GeneratedResearchArtifact;
  onInsertIntoManuscript?: (artifact: GeneratedResearchArtifact) => void;
};

type PreviewState =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'ready'; objectUrl: string; textContent?: string }
  | { status: 'error'; message: string };

function mimeForPath(path: string): string {
  const lower = path.toLowerCase();
  if (lower.endsWith('.pdf')) return 'application/pdf';
  if (lower.endsWith('.svg')) return 'image/svg+xml';
  if (lower.endsWith('.png')) return 'image/png';
  if (lower.endsWith('.jpg') || lower.endsWith('.jpeg')) return 'image/jpeg';
  if (lower.endsWith('.csv')) return 'text/csv;charset=utf-8';
  if (lower.endsWith('.tsv')) return 'text/tab-separated-values;charset=utf-8';
  if (lower.endsWith('.json')) return 'application/json;charset=utf-8';
  return 'application/octet-stream';
}

function canInsert(artifact: GeneratedResearchArtifact): boolean {
  if (artifact.kind === 'plot') return /\.(?:pdf|png|jpe?g|svg|eps)$/iu.test(artifact.path);
  return (artifact.kind === 'dataset' || artifact.kind === 'table') && /\.(?:csv|tsv)$/iu.test(artifact.path);
}

export function ResearchArtifactCard({ wsName, artifact, onInsertIntoManuscript }: Props) {
  const { fileSystem, navigation } = useCoreServices();
  const wsPath = React.useMemo(() => WsPath.fromParts(wsName, artifact.path).wsPath, [artifact.path, wsName]);
  const previewKind = React.useMemo(() => getAssetPreviewKind(wsPath), [wsPath]);
  const [expanded, setExpanded] = React.useState(false);
  const [preview, setPreview] = React.useState<PreviewState>({ status: 'idle' });

  React.useEffect(() => {
    if (!expanded || !previewKind) return undefined;
    let active = true;
    let objectUrl: string | undefined;
    setPreview({ status: 'loading' });
    void (async () => {
      try {
        const file = await fileSystem.readFile(wsPath);
        if (!file) throw new Error('Generated artifact is no longer available in the project.');
        const previewLimit = 256 * 1024;
        const source = previewKind === 'text' ? file.slice(0, previewLimit) : file;
        const bytes = await source.arrayBuffer();
        if (!active) return;
        const blob = new Blob([bytes], { type: mimeForPath(artifact.path) });
        objectUrl = URL.createObjectURL(blob);
        const textContent = previewKind === 'text'
          ? `${new TextDecoder().decode(bytes)}${file.size > previewLimit ? '\n…[preview truncated]' : ''}`
          : undefined;
        setPreview({ status: 'ready', objectUrl, ...(textContent !== undefined ? { textContent } : {}) });
      } catch (error) {
        if (active) setPreview({ status: 'error', message: error instanceof Error ? error.message : String(error) });
      }
    })();
    return () => {
      active = false;
      if (objectUrl) URL.revokeObjectURL(objectUrl);
    };
  }, [artifact.path, expanded, fileSystem, previewKind, wsPath]);

  const generatedAt = new Date(artifact.createdAt).toLocaleString();
  const generator = artifact.generatedBy?.sourcePath;

  return (
    <article className="rounded-md border bg-background p-2 font-sans text-xs" data-testid="research-artifact-card">
      <div className="flex flex-wrap items-start gap-2">
        <div className="mt-0.5 rounded bg-muted p-1.5"><FlaskConical className="size-3.5" /></div>
        <div className="min-w-0 flex-1">
          <div className="truncate font-medium" title={artifact.path}>{artifact.path}</div>
          <div className="mt-0.5 flex flex-wrap gap-x-2 text-[10px] text-muted-foreground">
            <span>{artifact.kind}</span>
            {artifact.generatedBy?.runtime && <span>{artifact.generatedBy.runtime}</span>}
            <span>{generatedAt}</span>
          </div>
          {generator && <div className="mt-1 truncate text-[10px] text-muted-foreground">Generated by {generator}</div>}
          {artifact.generatedBy?.inputPaths?.length ? (
            <div className="mt-0.5 truncate text-[10px] text-muted-foreground" title={artifact.generatedBy.inputPaths.join(', ')}>Inputs: {artifact.generatedBy.inputPaths.join(', ')}</div>
          ) : null}
          {artifact.generatedBy?.command ? (
            <div className="mt-0.5 truncate font-mono text-[10px] text-muted-foreground" title={artifact.generatedBy.command}>$ {artifact.generatedBy.command}</div>
          ) : null}
        </div>
        <div className="flex flex-wrap justify-end gap-1">
          {previewKind && (
            <Button size="sm" variant="ghost" className="h-7 px-2 text-[10px]" onClick={() => setExpanded((value) => !value)}>
              <Eye className="mr-1 size-3" />{expanded ? 'Hide' : 'Preview'}
            </Button>
          )}
          <Button size="sm" variant="ghost" className="h-7 px-2 text-[10px]" onClick={() => navigation.goWsPath(wsPath)}>
            <ExternalLink className="mr-1 size-3" />Open
          </Button>
          {generator && (
            <Button size="sm" variant="ghost" className="h-7 px-2 text-[10px]" onClick={() => navigation.goWsPath(WsPath.fromParts(wsName, generator).wsPath)}>
              <FileText className="mr-1 size-3" />Generator
            </Button>
          )}
          {canInsert(artifact) && onInsertIntoManuscript && (
            <Button size="sm" variant="outline" className="h-7 px-2 text-[10px]" onClick={() => onInsertIntoManuscript(artifact)}>
              <FileInput className="mr-1 size-3" />Insert into manuscript
            </Button>
          )}
        </div>
      </div>
      {expanded && (
        <div className="mt-2 overflow-hidden rounded border bg-muted/20 p-2">
          {preview.status === 'loading' && <div className="text-muted-foreground">Loading preview…</div>}
          {preview.status === 'error' && <div className="text-destructive">{preview.message}</div>}
          {preview.status === 'ready' && previewKind && (
            <div className={previewKind === 'pdf' ? 'max-h-72 overflow-hidden [&_iframe]:!h-64' : 'max-h-72 overflow-auto [&_img]:!max-h-64'}>
              <AssetPreview
                kind={previewKind}
                objectUrl={preview.objectUrl}
                fileName={artifact.path.split('/').at(-1) ?? artifact.path}
                textContent={preview.textContent}
              />
            </div>
          )}
        </div>
      )}
    </article>
  );
}
