import { useState } from "react";
import { ResultsTable } from "@/components/results/ResultsTable";
import { ExportDialog } from "@/components/export/ExportDialog";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import {
  ChevronDown,
  ChevronRight,
  AlertCircle,
  Sparkles,
  User,
  Database,
  Maximize2,
  Download,
} from "lucide-react";
import type { ChatMessage } from "@/types";
import { getToolMeta, isQueryResultTool } from "./tool-registry";

interface Props {
  message: ChatMessage;
}

export function ChatMessageView({ message }: Props) {
  switch (message.role) {
    case "user":
      return <UserBubble text={message.text} />;
    case "assistant":
      return <AssistantBubble text={message.text} />;
    case "tool_call":
      return <ToolCallBlock tool={message.tool} inputJson={message.input_json} />;
    case "tool_result":
      return (
        <ToolResultBlock
          tool={message.tool}
          isError={message.is_error}
          text={message.text ?? null}
          result={message.result ?? null}
        />
      );
  }
}

function UserBubble({ text }: { text: string }) {
  return (
    <div className="flex gap-2">
      <span className="mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground">
        <User className="h-3 w-3" />
      </span>
      <div className="flex-1 whitespace-pre-wrap rounded-md bg-accent/30 px-3 py-2 text-sm">
        {text}
      </div>
    </div>
  );
}

function AssistantBubble({ text }: { text: string }) {
  return (
    <div className="flex gap-2">
      <span className="mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary">
        <Sparkles className="h-3 w-3" />
      </span>
      <div className="flex-1 whitespace-pre-wrap text-sm leading-relaxed">{text}</div>
    </div>
  );
}

function ToolCallBlock({ tool, inputJson }: { tool: string; inputJson: string }) {
  const [expanded, setExpanded] = useState(false);
  const meta = getToolMeta(tool);
  const preview = previewFromJson(tool, inputJson);
  const Icon = meta.icon;
  const showSqlPreview = (tool === "run_query" || tool === "explain_query") && preview;

  return (
    <div className="ml-8 rounded-md border border-border/40 bg-muted/20">
      <button
        type="button"
        className="flex w-full items-center gap-1.5 px-2 py-1.5 text-xs text-muted-foreground hover:text-foreground"
        onClick={() => setExpanded((v) => !v)}
      >
        {expanded ? <ChevronDown className="h-3 w-3" /> : <ChevronRight className="h-3 w-3" />}
        <Icon className="h-3 w-3" />
        <span className="font-medium">{meta.label}</span>
        {preview && (
          <span className="ml-1 truncate text-muted-foreground/70">{preview}</span>
        )}
      </button>
      {expanded && (
        <div className="border-t border-border/30 p-2">
          {showSqlPreview ? (
            <pre className="overflow-x-auto whitespace-pre-wrap rounded bg-background/60 p-2 font-mono text-[11px]">
              {preview}
            </pre>
          ) : (
            <pre className="overflow-x-auto rounded bg-background/60 p-2 font-mono text-[11px]">
              {prettyJson(inputJson)}
            </pre>
          )}
        </div>
      )}
    </div>
  );
}

function previewFromJson(tool: string, inputJson: string): string | null {
  try {
    const parsed = JSON.parse(inputJson) as Record<string, unknown>;
    return getToolMeta(tool).preview(parsed);
  } catch {
    return null;
  }
}

function ToolResultBlock({
  tool,
  isError,
  text,
  result,
}: {
  tool: string;
  isError: boolean;
  text: string | null;
  result: { columns: string[]; types: string[]; rows: unknown[][]; row_count: number; execution_time_ms: number } | null;
}) {
  if (isError) {
    return (
      <div className="ml-8 flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/5 px-3 py-2 text-xs">
        <AlertCircle className="mt-0.5 h-3.5 w-3.5 shrink-0 text-destructive" />
        <div>
          <div className="font-medium text-destructive">{getToolMeta(tool).label} failed</div>
          {text && <div className="mt-1 whitespace-pre-wrap text-muted-foreground">{text}</div>}
        </div>
      </div>
    );
  }

  // Tools that produce a QueryResult (rendered as a table): run_query, sample_data.
  if (isQueryResultTool(tool) && result) {
    return <RunQueryResultBlock result={result} />;
  }

  // Everything else falls back to a collapsible text block.
  return <TextToolResult tool={tool} text={text} />;
}

function RunQueryResultBlock({
  result,
}: {
  result: {
    columns: string[];
    types: string[];
    rows: unknown[][];
    row_count: number;
    execution_time_ms: number;
  };
}) {
  const cap = 100;
  const [fullOpen, setFullOpen] = useState(false);
  const [exportOpen, setExportOpen] = useState(false);
  const previewRows = result.rows.slice(0, cap);
  const hasMore = result.rows.length > cap;

  return (
    <>
      <div className="ml-8 overflow-hidden rounded-md border border-border/40 bg-background">
        <div className="flex items-center gap-2 border-b border-border/30 px-2 py-1 text-[11px] text-muted-foreground">
          <Database className="h-3 w-3" />
          <span>
            {result.row_count} row{result.row_count === 1 ? "" : "s"} ·{" "}
            {result.execution_time_ms} ms
          </span>
          {hasMore && (
            <span className="text-muted-foreground/60">· showing first {cap}</span>
          )}
          <div className="ml-auto flex items-center gap-1">
            <Button
              size="icon-xs"
              variant="ghost"
              className="h-5 w-5 text-muted-foreground hover:text-foreground"
              onClick={() => setFullOpen(true)}
              title="Open full result"
              disabled={result.rows.length === 0}
            >
              <Maximize2 className="h-3 w-3" />
            </Button>
            <Button
              size="icon-xs"
              variant="ghost"
              className="h-5 w-5 text-muted-foreground hover:text-foreground"
              onClick={() => setExportOpen(true)}
              title="Export"
              disabled={result.rows.length === 0}
            >
              <Download className="h-3 w-3" />
            </Button>
          </div>
        </div>
        <div className="max-h-72 overflow-auto">
          <ResultsTable
            columns={result.columns}
            types={result.types}
            rows={previewRows}
          />
        </div>
      </div>

      <Dialog open={fullOpen} onOpenChange={setFullOpen}>
        <DialogContent className="flex h-[80vh] max-w-[90vw] flex-col gap-2 sm:max-w-[90vw]">
          <DialogHeader>
            <DialogTitle className="flex items-center gap-2 text-sm">
              <Database className="h-3.5 w-3.5" />
              Full result · {result.row_count} row{result.row_count === 1 ? "" : "s"} ·{" "}
              {result.execution_time_ms} ms
              <Button
                size="xs"
                variant="outline"
                className="ml-auto gap-1.5"
                onClick={() => setExportOpen(true)}
              >
                <Download className="h-3 w-3" />
                Export
              </Button>
            </DialogTitle>
          </DialogHeader>
          <div className="min-h-0 flex-1 overflow-hidden rounded-md border border-border/40">
            <ResultsTable
              columns={result.columns}
              types={result.types}
              rows={result.rows}
            />
          </div>
        </DialogContent>
      </Dialog>

      <ExportDialog
        open={exportOpen}
        onOpenChange={setExportOpen}
        columns={result.columns}
        rows={result.rows}
      />
    </>
  );
}

function TextToolResult({ tool, text }: { tool: string; text: string | null }) {
  // Lazy preview: switch_database is short; everything else collapses by default.
  const [expanded, setExpanded] = useState(tool === "switch_database");
  const meta = getToolMeta(tool);
  const Icon = meta.icon;
  const lineCount = text ? text.split("\n").length : 0;

  return (
    <div className="ml-8 rounded-md border border-border/40 bg-muted/20">
      <button
        type="button"
        className="flex w-full items-center gap-1.5 px-2 py-1.5 text-xs text-muted-foreground hover:text-foreground"
        onClick={() => setExpanded((v) => !v)}
      >
        {expanded ? <ChevronDown className="h-3 w-3" /> : <ChevronRight className="h-3 w-3" />}
        <Icon className="h-3 w-3" />
        <span className="font-medium">{meta.label}</span>
        {text && (
          <span className="ml-1 text-muted-foreground/60">
            {lineCount} line{lineCount === 1 ? "" : "s"}
          </span>
        )}
      </button>
      {expanded && text && (
        <div className="border-t border-border/30 p-2">
          <pre className="max-h-72 overflow-auto whitespace-pre-wrap rounded bg-background/60 p-2 font-mono text-[11px] leading-relaxed">
            {text}
          </pre>
        </div>
      )}
    </div>
  );
}

function prettyJson(s: string): string {
  try {
    return JSON.stringify(JSON.parse(s), null, 2);
  } catch {
    return s;
  }
}
