"use client";

import * as React from "react";
import type { inferRouterOutputs } from "@trpc/server";
import { Loader2, Send, Sparkles, X } from "lucide-react";

import { cn } from "@/lib/utils";
import { api } from "@/lib/trpc";
import type { aiRouter } from "@/server/routers/ai";
import { usePanelStore } from "@/lib/stores/panel-store";
import { useWorkspaceStore } from "@/lib/stores/workspace-store";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { ScrollArea } from "@/components/ui/scroll-area";
import { AIMessage } from "@/components/ai/message";

type ChatRole = "user" | "assistant";

type ChatLine = {
  id: string;
  role: ChatRole;
  content: string;
  createdAt: Date;
};

type ObjectSummary = { title: string; type: string };
type AiOutputs = inferRouterOutputs<typeof aiRouter>;

/** Cast until `aiRouter` is merged into `appRouter` in `server/root.ts` */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const aiTrpc = (api as any).ai as {
  suggestActions: {
    useQuery: (
      input: { workspace: string; objectId?: string; objectType?: string },
      opts?: { enabled?: boolean },
    ) => { data: { actions: string[] } | undefined };
  };
  chat: {
    useMutation: (opts: {
      onMutate?: () => void;
      onSuccess?: (data: AiOutputs["chat"]) => void;
      onError?: (err: { message: string }) => void;
    }) => {
      mutate: (input: {
        workspace: string;
        messages: { role: "user" | "assistant"; content: string }[];
        context?: { objectId?: string };
      }) => void;
      isPending: boolean;
      isError: boolean;
      error: { message: string } | null;
    };
  };
};

const MODEL_LABEL = "GPT-4o";
const MAX_CHARS = 8000;

const WELCOME_CHIPS = [
  "Create a project plan",
  "Summarize this document",
  "Generate task descriptions",
];

function TypingDots() {
  return (
    <div className="flex items-center gap-1.5 px-1 py-2" aria-hidden>
      {[0, 1, 2].map((i) => (
        <span
          key={i}
          className="inline-block h-2 w-2 animate-bounce rounded-full bg-muted-foreground/70"
          style={{ animationDelay: `${i * 0.15}s` }}
        />
      ))}
    </div>
  );
}

export function AIChatPanel() {
  const close = usePanelStore((s) => s.close);
  const objectId = usePanelStore((s) => s.objectId);
  const workspace = useWorkspaceStore((s) => s.currentWorkspace);

  const [input, setInput] = React.useState("");
  const [messages, setMessages] = React.useState<ChatLine[]>([]);
  const [sendError, setSendError] = React.useState<string | null>(null);
  const bottomRef = React.useRef<HTMLDivElement>(null);
  const textareaRef = React.useRef<HTMLTextAreaElement>(null);

  const workspaceHandle = workspace?.slug ?? workspace?.id;

  const objectQuery = api.objects.getById.useQuery(
    { id: objectId!, workspace: workspaceHandle! },
    { enabled: !!objectId && Boolean(workspaceHandle) },
  );

  const objectSummary = objectQuery.data as ObjectSummary | undefined;

  const suggestQuery = aiTrpc.suggestActions.useQuery(
    {
      workspace: workspaceHandle!,
      objectId: objectId ?? undefined,
      objectType: objectSummary?.type,
    },
    { enabled: Boolean(workspaceHandle) },
  );

  const chatMutation = aiTrpc.chat.useMutation({
    onMutate: () => setSendError(null),
    onSuccess: (data) => {
      setMessages((prev) => [
        ...prev,
        {
          id: crypto.randomUUID(),
          role: "assistant",
          content: data.text,
          createdAt: new Date(),
        },
      ]);
    },
    onError: (err) => setSendError(err.message ?? "Request failed"),
  });

  const isLoading = chatMutation.isPending;

  React.useEffect(() => {
    bottomRef.current?.scrollIntoView({ behavior: "smooth" });
  }, [messages, isLoading]);

  const send = React.useCallback(() => {
    const trimmed = input.trim();
    if (!trimmed || isLoading) return;

    const userMsg: ChatLine = {
      id: crypto.randomUUID(),
      role: "user",
      content: trimmed,
      createdAt: new Date(),
    };

    const nextMessages = [...messages, userMsg];
    setMessages(nextMessages);
    setInput("");

    const payload = nextMessages.map((m) => ({
      role: m.role,
      content: m.content,
    }));

    if (!workspaceHandle) {
      setSendError("Select a workspace first.");
      return;
    }
    chatMutation.mutate({
      workspace: workspaceHandle,
      messages: payload,
      context: {
        objectId: objectId ?? undefined,
      },
    });
  }, [input, isLoading, messages, chatMutation, workspaceHandle, objectId]);

  const onKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
    if (e.key === "Enter" && !e.shiftKey) {
      e.preventDefault();
      send();
    }
  };

  const insertChip = (text: string) => {
    setInput((prev) => (prev ? `${prev}\n${text}` : text));
    textareaRef.current?.focus();
  };

  const contextLabel = objectSummary?.title
    ? objectSummary.title
    : workspace?.name
      ? workspace.name
      : "No context";

  const suggestions = suggestQuery.data?.actions ?? [];

  return (
    <div className="flex h-full min-h-0 flex-col bg-background">
      <header className="flex shrink-0 items-start justify-between gap-2 border-b border-border/80 px-4 py-3">
        <div className="min-w-0 space-y-1">
          <div className="flex items-center gap-2">
            <Sparkles className="size-5 shrink-0 text-primary" />
            <h2 className="truncate text-base font-semibold tracking-tight">AI Assistant</h2>
          </div>
          <div className="flex flex-wrap items-center gap-2">
            <Badge variant="secondary" className="font-normal">
              {MODEL_LABEL}
            </Badge>
            <span
              className="truncate text-xs text-muted-foreground"
              title={contextLabel}
            >
              {objectId ? "Object: " : "Workspace: "}
              <span className="text-foreground/90">{contextLabel}</span>
            </span>
          </div>
        </div>
        <Button
          type="button"
          variant="ghost"
          size="icon"
          className="shrink-0"
          onClick={() => close()}
          aria-label="Close panel"
        >
          <X className="size-4" />
        </Button>
      </header>

      <ScrollArea className="min-h-0 flex-1 px-3">
        <div className="pb-4 pt-2">
          {messages.length === 0 && !isLoading ? (
            <div className="space-y-4 px-1">
              <div className="rounded-2xl border border-dashed border-primary/25 bg-primary/5 px-4 py-6 text-center dark:bg-primary/10">
                <p className="text-sm font-medium text-foreground">How can I help?</p>
                <p className="mt-1 text-xs text-muted-foreground">
                  Ask about planning, tasks, or this workspace — or try a suggestion below.
                </p>
              </div>
              <div className="flex flex-col gap-2">
                <p className="text-xs font-medium text-muted-foreground">Try asking</p>
                <div className="flex flex-wrap gap-2">
                  {WELCOME_CHIPS.map((chip) => (
                    <button
                      key={chip}
                      type="button"
                      onClick={() => insertChip(chip)}
                      className="rounded-full border border-border bg-card px-3 py-1.5 text-left text-xs transition-colors hover:bg-accent"
                    >
                      {chip}
                    </button>
                  ))}
                </div>
              </div>
            </div>
          ) : null}

          {messages.map((m) => (
            <AIMessage
              key={m.id}
              role={m.role}
              content={m.content}
              timestamp={m.createdAt}
            />
          ))}

          {sendError ? (
            <AIMessage role="system" content={sendError} />
          ) : null}

          {isLoading ? (
            <div className="flex items-start gap-3 px-1 py-2">
              <div className="mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-full border border-border/60 bg-teal-500/15 text-teal-600 dark:text-teal-400">
                <Sparkles className="size-4" />
              </div>
              <div className="rounded-2xl rounded-tl-md border border-border/80 bg-card px-4 py-3">
                <TypingDots />
                <span className="sr-only">Assistant is thinking</span>
              </div>
            </div>
          ) : null}

          <div ref={bottomRef} />
        </div>
      </ScrollArea>

      <div className="shrink-0 border-t border-border/80 bg-muted/20 px-3 pb-3 pt-2">
        {suggestions.length > 0 ? (
          <div className="mb-2 flex flex-wrap gap-1.5">
            {suggestions.slice(0, 6).map((action) => (
              <button
                key={action}
                type="button"
                onClick={() => insertChip(action)}
                className={cn(
                  "rounded-full border border-primary/20 bg-background/80 px-2.5 py-1 text-xs text-foreground",
                  "transition-colors hover:border-primary/40 hover:bg-primary/5",
                )}
              >
                {action}
              </button>
            ))}
          </div>
        ) : null}

        <div className="flex gap-2">
          <div className="relative min-w-0 flex-1">
            <textarea
              ref={textareaRef}
              value={input}
              onChange={(e) => setInput(e.target.value.slice(0, MAX_CHARS))}
              onKeyDown={onKeyDown}
              placeholder="Ask AI anything..."
              disabled={isLoading}
              rows={3}
              className={cn(
                "w-full resize-none rounded-xl border border-input bg-background px-3 py-2.5 text-sm",
                "placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
                "disabled:cursor-not-allowed disabled:opacity-50",
              )}
            />
            <div className="pointer-events-none absolute bottom-2 right-2 text-[10px] text-muted-foreground">
              {input.length}/{MAX_CHARS}
            </div>
          </div>
          <Button
            type="button"
            size="icon"
            className="h-auto min-h-[5.5rem] shrink-0 rounded-xl bg-primary"
            onClick={send}
            disabled={isLoading || !input.trim()}
            aria-label="Send message"
          >
            {isLoading ? (
              <Loader2 className="size-5 animate-spin" />
            ) : (
              <Send className="size-5" />
            )}
          </Button>
        </div>
      </div>
    </div>
  );
}
