import { useState, useCallback } from 'react';
import { Link } from 'react-router';
import { useQuery } from '@tanstack/react-query';
import { Globe, RefreshCw, Send, Terminal, Loader2 } from 'lucide-react';
import { toast } from 'sonner';
import { Button } from '@/components/ui/button';
import { useClient } from 'hooks/useClient';
import { useBrowserTargets, useSelectedTabId } from './shared';

export const TabPreview = () => {
  const client = useClient();
  // Reads the URL itself rather than being told by the list.
  const selectedId = useSelectedTabId();
  const { data: targets } = useBrowserTargets(!!selectedId);
  // A target id dies with the browser session, so a link or a reload can name a tab that is no longer
  // attached. Screenshotting it would 404 every ten seconds; better to say so once.
  const isKnownTab = !!selectedId && !!targets?.some((t) => t.id === selectedId);
  const [navUrl, setNavUrl] = useState('');
  const [evalExpr, setEvalExpr] = useState('');
  const [evalResult, setEvalResult] = useState<string | null>(null);
  const [isNavigating, setIsNavigating] = useState(false);
  const [isEvaluating, setIsEvaluating] = useState(false);

  const {
    data: screenshot,
    isLoading,
    refetch,
    isFetching,
  } = useQuery({
    queryKey: ['browser-screenshot', selectedId],
    queryFn: () => client.get<{ data: string; format: string }>(`/browser/targets/${selectedId}/screenshot`),
    enabled: isKnownTab,
    refetchInterval: 10000,
  });

  const handleNavigate = useCallback(async () => {
    if (!selectedId || !navUrl.trim()) return;
    setIsNavigating(true);
    try {
      await client.post(`/browser/targets/${selectedId}/navigate`, { url: navUrl.trim() });
      setTimeout(() => void refetch(), 1000);
    } catch {
      toast.error('Navigation failed');
    } finally {
      setIsNavigating(false);
    }
  }, [client, selectedId, navUrl, refetch]);

  const handleEvaluate = useCallback(async () => {
    if (!selectedId || !evalExpr.trim()) return;
    setIsEvaluating(true);
    try {
      const res = await client.post<{ result: unknown }>(`/browser/targets/${selectedId}/evaluate`, {
        expression: evalExpr.trim(),
      });
      setEvalResult(JSON.stringify(res.result, null, 2));
    } catch (err) {
      setEvalResult(`Error: ${err instanceof Error ? err.message : String(err)}`);
    } finally {
      setIsEvaluating(false);
    }
  }, [client, selectedId, evalExpr]);

  if (!selectedId) {
    return (
      <div className="flex h-full flex-col items-center justify-center gap-2 text-sm opacity-50">
        <Globe className="h-8 w-8" />
        <span>Select a tab to preview</span>
      </div>
    );
  }

  // Waiting on the list is not the same as knowing the tab is gone, so only say so once it has arrived.
  if (targets && !isKnownTab) {
    return (
      <div className="flex h-full flex-col items-center justify-center gap-2 text-sm opacity-50">
        <Globe className="h-8 w-8" />
        <span>That tab is no longer attached</span>
        <Link to="/browser" className="text-xs underline">
          Back to the tab list
        </Link>
      </div>
    );
  }

  return (
    <div className="flex h-full flex-col overflow-hidden">
      {/* URL bar */}
      <div className="flex items-center gap-2 border-b px-3 py-2">
        <Button
          variant="ghost"
          size="sm"
          className="h-7 w-7 p-0 shrink-0"
          onClick={() => void refetch()}
          disabled={isFetching}
        >
          {isFetching ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <RefreshCw className="h-3.5 w-3.5" />}
        </Button>
        <form
          className="flex flex-1 items-center gap-2"
          onSubmit={(ev) => {
            ev.preventDefault();
            void handleNavigate();
          }}
        >
          <input
            type="text"
            value={navUrl}
            onChange={(ev) => setNavUrl(ev.target.value)}
            placeholder="Navigate to URL..."
            className="flex-1 rounded-md border bg-transparent px-2 py-1 text-sm outline-none focus:border-cyan-500"
          />
          <Button
            variant="ghost"
            size="sm"
            className="h-7 w-7 p-0 shrink-0"
            type="submit"
            disabled={isNavigating || !navUrl.trim()}
          >
            <Send className="h-3.5 w-3.5" />
          </Button>
        </form>
      </div>

      {/* Screenshot */}
      <div className="flex-1 overflow-auto p-2">
        {isLoading && !screenshot && (
          <div className="flex h-full items-center justify-center">
            <Loader2 className="h-6 w-6 animate-spin opacity-50" />
          </div>
        )}
        {screenshot && (
          <img
            src={`data:image/${screenshot.format};base64,${screenshot.data}`}
            alt="Tab screenshot"
            className="w-full rounded-md border"
          />
        )}
      </div>

      {/* JS Console */}
      <div className="border-t">
        <form
          className="flex items-center gap-2 px-3 py-2"
          onSubmit={(ev) => {
            ev.preventDefault();
            void handleEvaluate();
          }}
        >
          <Terminal className="h-3.5 w-3.5 shrink-0 opacity-50" />
          <input
            type="text"
            value={evalExpr}
            onChange={(ev) => setEvalExpr(ev.target.value)}
            placeholder="Evaluate JavaScript..."
            className="flex-1 bg-transparent text-sm outline-none font-mono"
          />
          <Button
            variant="ghost"
            size="sm"
            className="h-6 px-2 shrink-0"
            type="submit"
            disabled={isEvaluating || !evalExpr.trim()}
          >
            {isEvaluating ? <Loader2 className="h-3 w-3 animate-spin" /> : 'Run'}
          </Button>
        </form>
        {evalResult !== null && (
          <pre className="max-h-32 overflow-auto border-t px-3 py-2 text-xs font-mono opacity-70">{evalResult}</pre>
        )}
      </div>
    </div>
  );
};
