import { useCoreServices } from '@learnitive/context';
import { Button, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@learnitive/ui-components';
import { LoaderCircle, Play, RotateCcw } from 'lucide-react';
import React from 'react';

export type MarkdownCodeRunRequest = {
  language: string;
  sourceLanguage?: string;
  code: string;
};

const SNIPPET_FILENAMES: Record<string, string> = {
  c: 'main.c',
  cpp: 'main.cpp',
  go: 'main.go',
  java: 'Main.java',
  javascript: 'main.js',
  php: 'main.php',
  python: 'main.py',
  r: 'main.R',
  ruby: 'main.rb',
  rust: 'main.rs',
  shell: 'main.sh',
  typescript: 'main.ts',
};

export function MarkdownCodeRunDialog({
  wsName,
  request,
  onOpenChange,
}: {
  wsName: string;
  request?: MarkdownCodeRunRequest;
  onOpenChange: (open: boolean) => void;
}) {
  const core = useCoreServices();
  const [stdin, setStdin] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const [result, setResult] = React.useState<{ exitCode: number | null; stdout: string; stderr: string }>();
  const [error, setError] = React.useState('');

  React.useEffect(() => {
    setStdin('');
    setResult(undefined);
    setError('');
  }, [request?.code, request?.language]);

  const run = React.useCallback(async () => {
    if (!request || busy) return;
    setBusy(true);
    setError('');
    try {
      const result = await core.projectExecution.executeSnippet(wsName, {
        projectModeId: request.language,
        language: request.language,
        filename: SNIPPET_FILENAMES[request.language],
        code: request.code,
        stdin,
      });
      setResult({ exitCode: result.exitCode, stdout: result.stdout, stderr: result.stderr });
    } catch (reason) {
      setError(reason instanceof Error ? reason.message : String(reason));
      setResult(undefined);
    } finally {
      setBusy(false);
    }
  }, [busy, core.projectExecution, request, stdin, wsName]);

  return (
    <Dialog open={Boolean(request)} onOpenChange={(open) => !busy && onOpenChange(open)}>
      <DialogContent className="sm:max-w-2xl" data-testid="markdown-code-run-dialog">
        <DialogHeader>
          <DialogTitle>Run code block</DialogTitle>
          <DialogDescription>
            Run this {request?.sourceLanguage || request?.language || 'code'} block through the same bounded Learnitive runtime used by code projects. Nothing is written into your Markdown.
          </DialogDescription>
        </DialogHeader>
        <div className="grid gap-3">
          <pre className="max-h-64 overflow-auto rounded-md border bg-muted/30 p-3 text-xs"><code>{request?.code || ''}</code></pre>
          <label className="grid gap-1.5 text-sm">
            <span className="font-medium">Standard input <span className="font-normal text-muted-foreground">(optional)</span></span>
            <textarea
              className="min-h-24 resize-y rounded-md border bg-background p-2 font-mono text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring"
              value={stdin}
              onChange={(event) => setStdin(event.currentTarget.value.slice(0, 1_000_000))}
              spellCheck={false}
              placeholder="Input passed to stdin for this run"
              aria-label="Code block standard input"
            />
          </label>
          {error ? <div className="rounded-md border border-destructive/30 bg-destructive/5 p-3 text-sm text-destructive" role="alert">{error}</div> : null}
          {result ? <section className="grid gap-2 rounded-md border bg-muted/20 p-3" aria-live="polite">
            <strong className="text-sm">Exit {result.exitCode ?? '—'}</strong>
            {result.stdout ? <pre className="max-h-56 overflow-auto whitespace-pre-wrap rounded bg-background p-2 font-mono text-xs">{result.stdout}</pre> : null}
            {result.stderr ? <pre className="max-h-56 overflow-auto whitespace-pre-wrap rounded bg-background p-2 font-mono text-xs text-destructive">{result.stderr}</pre> : null}
            {!result.stdout && !result.stderr ? <p className="text-sm text-muted-foreground">No output.</p> : null}
          </section> : null}
        </div>
        <DialogFooter>
          <Button type="button" variant="outline" disabled={busy} onClick={() => onOpenChange(false)}>Close</Button>
          <Button type="button" disabled={busy || !request?.code.trim()} onClick={() => void run()}>
            {busy ? <LoaderCircle className="mr-1 size-4 animate-spin" /> : result ? <RotateCcw className="mr-1 size-4" /> : <Play className="mr-1 size-4" />}
            {busy ? 'Running…' : result ? 'Run again' : 'Run'}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
