"use client";

/*
 * Style-agent chat panel — the new "שיחה" tab on /training.
 *
 * Layout: two columns.
 *   - Sidebar: list of conversations + "+ שיחה חדשה" button
 *   - Main: thread of messages + composer with SSE streaming
 *
 * Each message is persisted to the legal-ai DB; the LLM call goes
 * out via FastAPI → host's legal-chat-service → claude CLI. There
 * is no API cost — the claude CLI uses Daphna's claude.ai
 * subscription via the host's auth.
 *
 * Health gate: if /api/training/chat/health reports the host service
 * is unreachable, the composer is replaced by a setup notice telling
 * the chair to start the pm2 service.
 */

import { useEffect, useRef, useState } from "react";
import {
  Send, Plus, Trash2, Loader2, MessageSquare, Sparkles, AlertTriangle,
} from "lucide-react";
import { toast } from "sonner";
import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Textarea } from "@/components/ui/textarea";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Badge } from "@/components/ui/badge";
import { Skeleton } from "@/components/ui/skeleton";
import {
  Select, SelectContent, SelectItem, SelectTrigger, SelectValue,
} from "@/components/ui/select";
import {
  chatKeys,
  useChatConversation,
  useChatConversations,
  useChatHealth,
  useCorpus,
  useCreateChat,
  useDeleteChat,
  type ChatMessage,
} from "@/lib/api/training";
import { useQueryClient } from "@tanstack/react-query";

export function ChatPanel() {
  const [activeId, setActiveId] = useState<string | null>(null);
  const health = useChatHealth();

  return (
    <div className="grid gap-4 lg:grid-cols-[280px_1fr]">
      <ConversationsSidebar activeId={activeId} onSelect={setActiveId} />
      <div className="space-y-3">
        {health.data && !health.data.reachable && (
          <ChatServiceWarning health={health.data} />
        )}
        {activeId ? (
          <ChatThread convId={activeId} />
        ) : (
          <Card className="bg-rule-soft/40 border-rule">
            <CardContent className="px-6 py-10 text-center text-ink-muted text-sm space-y-2">
              <MessageSquare className="w-8 h-8 mx-auto opacity-50" />
              <p>בחר שיחה קיימת או פתח חדשה כדי להתחיל לדבר עם סוכן הסגנון.</p>
              <p className="text-[0.78rem]">
                הסוכן רץ על claude CLI מקומי דרך legal-chat-service. אין עלות API.
              </p>
            </CardContent>
          </Card>
        )}
      </div>
    </div>
  );
}

// ── Sidebar: list + new ────────────────────────────────────────────

function ConversationsSidebar({
  activeId, onSelect,
}: {
  activeId: string | null;
  onSelect: (id: string | null) => void;
}) {
  const { data: convs, isPending } = useChatConversations();
  const { data: corpus } = useCorpus();
  const create = useCreateChat();
  const del = useDeleteChat();
  const [creating, setCreating] = useState(false);
  const [newTitle, setNewTitle] = useState("");
  const [newCorpusId, setNewCorpusId] = useState<string>("__none__");

  const onCreate = async () => {
    try {
      const conv = await create.mutateAsync({
        title: newTitle.trim() || "שיחה חדשה",
        style_corpus_id: newCorpusId === "__none__" ? null : newCorpusId,
      });
      onSelect(conv.id);
      setCreating(false);
      setNewTitle("");
      setNewCorpusId("__none__");
    } catch (e) {
      toast.error(e instanceof Error ? e.message : "כשל ביצירת שיחה");
    }
  };

  const onDelete = async (id: string) => {
    if (!window.confirm("למחוק את השיחה? פעולה זו לא ניתנת לביטול.")) return;
    try {
      await del.mutateAsync(id);
      if (activeId === id) onSelect(null);
      toast.success("השיחה נמחקה");
    } catch (e) {
      toast.error(e instanceof Error ? e.message : "כשל במחיקה");
    }
  };

  return (
    <Card className="bg-surface border-rule">
      <CardContent className="px-3 py-3 space-y-2">
        {!creating ? (
          <Button
            onClick={() => setCreating(true)}
            className="w-full bg-navy text-parchment hover:bg-navy-soft"
            size="sm"
          >
            <Plus className="w-4 h-4 me-1" />
            שיחה חדשה
          </Button>
        ) : (
          <div className="space-y-2 border border-rule rounded p-2 bg-rule-soft/30">
            <Textarea
              value={newTitle}
              onChange={(e) => setNewTitle(e.target.value)}
              placeholder="כותרת לשיחה (אופציונלי)"
              rows={2} dir="rtl"
            />
            <Select value={newCorpusId} onValueChange={setNewCorpusId} dir="rtl">
              <SelectTrigger>
                <SelectValue placeholder="צמד להחלטה (אופציונלי)" />
              </SelectTrigger>
              <SelectContent className="max-h-[300px]">
                <SelectItem value="__none__">— שיחה כללית —</SelectItem>
                {corpus?.map((c) => (
                  <SelectItem key={c.id} value={c.id}>
                    {c.decision_number || "—"}
                    {c.decision_date ? ` · ${c.decision_date}` : ""}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
            <div className="flex gap-1 justify-end">
              <Button variant="ghost" size="sm"
                onClick={() => { setCreating(false); setNewTitle(""); setNewCorpusId("__none__"); }}>
                ביטול
              </Button>
              <Button size="sm" onClick={onCreate} disabled={create.isPending}
                className="bg-navy text-parchment hover:bg-navy-soft">
                צור
              </Button>
            </div>
          </div>
        )}

        <ScrollArea className="h-[520px]">
          <ul className="space-y-1">
            {isPending && (
              <>
                <Skeleton className="h-12 w-full" />
                <Skeleton className="h-12 w-full" />
              </>
            )}
            {convs?.length === 0 && (
              <p className="text-center text-ink-muted text-[0.78rem] py-6">
                אין עדיין שיחות
              </p>
            )}
            {convs?.map((c) => {
              const active = c.id === activeId;
              return (
                <li key={c.id}>
                  <button
                    onClick={() => onSelect(c.id)}
                    className={
                      "w-full text-end rounded-md px-2 py-2 transition " +
                      (active
                        ? "bg-gold-wash border border-gold/40"
                        : "hover:bg-rule-soft/60 border border-transparent")
                    }
                  >
                    <div className="text-sm text-navy font-semibold truncate">
                      {c.title}
                    </div>
                    <div className="flex items-center gap-1 text-[0.7rem] text-ink-muted">
                      {c.decision_number && (
                        <Badge variant="outline"
                          className="text-[0.65rem] bg-info-bg text-info border-info/40">
                          {c.decision_number}
                        </Badge>
                      )}
                      <span className="tabular-nums">{c.message_count}</span>
                      <MessageSquare className="w-3 h-3" />
                      <span className="grow text-end">
                        {new Date(c.last_message_at).toLocaleDateString("he-IL")}
                      </span>
                      <button
                        onClick={(e) => { e.stopPropagation(); onDelete(c.id); }}
                        className="hover:text-danger"
                        aria-label="מחק שיחה"
                      >
                        <Trash2 className="w-3 h-3" />
                      </button>
                    </div>
                  </button>
                </li>
              );
            })}
          </ul>
        </ScrollArea>
      </CardContent>
    </Card>
  );
}

// ── Thread + composer ──────────────────────────────────────────────

function ChatThread({ convId }: { convId: string }) {
  const { data, isPending } = useChatConversation(convId);
  const qc = useQueryClient();
  const [draft, setDraft] = useState("");
  const [streaming, setStreaming] = useState(false);
  const [streamingText, setStreamingText] = useState("");
  const [streamError, setStreamError] = useState("");
  const scrollRef = useRef<HTMLDivElement | null>(null);

  /* Auto-scroll to bottom when new messages arrive. */
  useEffect(() => {
    const el = scrollRef.current;
    if (!el) return;
    el.scrollTo({ top: el.scrollHeight, behavior: "smooth" });
  }, [data?.messages.length, streamingText]);

  const onSend = async () => {
    const text = draft.trim();
    if (!text || streaming) return;
    setDraft("");
    setStreaming(true);
    setStreamingText("");
    setStreamError("");

    try {
      const res = await fetch(
        `/api/training/chat/conversations/${encodeURIComponent(convId)}/messages`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ content: text }),
        },
      );
      if (!res.ok || !res.body) {
        const body = await res.text();
        throw new Error(`HTTP ${res.status}: ${body.slice(0, 200)}`);
      }
      // Parse SSE line-by-line. EventSource would be cleaner but it
      // doesn't support POST bodies; the manual reader is small.
      const reader = res.body.getReader();
      const decoder = new TextDecoder();
      let buffer = "";
      let accumulated = "";
      while (true) {
        const { value, done } = await reader.read();
        if (done) break;
        buffer += decoder.decode(value, { stream: true });
        let nl: number;
        while ((nl = buffer.indexOf("\n\n")) !== -1) {
          const event = buffer.slice(0, nl);
          buffer = buffer.slice(nl + 2);
          if (!event.startsWith("data: ")) continue;
          try {
            const payload = JSON.parse(event.slice("data: ".length));
            if (payload.type === "text_delta" && payload.text) {
              accumulated += payload.text;
              setStreamingText(accumulated);
            } else if (payload.type === "error") {
              setStreamError(String(payload.message || "שגיאה לא ידועה"));
            } else if (payload.type === "done") {
              if (payload.text && !accumulated) {
                accumulated = payload.text;
                setStreamingText(accumulated);
              }
            }
          } catch {
            /* ignore non-JSON */
          }
        }
      }
    } catch (e) {
      setStreamError(e instanceof Error ? e.message : "שגיאה בשיחה");
    } finally {
      setStreaming(false);
      setStreamingText("");
      // Refetch the conversation so the persisted assistant turn shows up.
      qc.invalidateQueries({ queryKey: chatKeys.conversation(convId) });
      qc.invalidateQueries({ queryKey: chatKeys.conversations() });
    }
  };

  if (isPending) return <Skeleton className="h-[560px] w-full" />;
  if (!data) return null;

  return (
    <Card className="bg-surface border-rule">
      <CardContent className="px-4 py-3 space-y-3">
        <header className="flex items-center gap-2 border-b border-rule pb-2">
          <Sparkles className="w-4 h-4 text-gold-deep" />
          <h3 className="text-navy font-semibold grow">{data.conversation.title}</h3>
          {data.conversation.decision_number && (
            <Badge variant="outline" className="bg-info-bg text-info border-info/40">
              {data.conversation.decision_number}
            </Badge>
          )}
        </header>

        <div ref={scrollRef} className="h-[440px] overflow-y-auto space-y-3 pe-1">
          {data.messages.length === 0 && !streaming && (
            <p className="text-center text-ink-muted text-sm py-8">
              התחל בשאלה — למשל: &quot;מה מאפיין את הפתיחות של דפנה בעררי 1xxx?&quot;
            </p>
          )}
          {data.messages.map((m) => <MessageBubble key={m.id} message={m} />)}
          {streaming && (
            <MessageBubble
              message={{
                id: "streaming",
                role: "assistant",
                content: streamingText || "(מקליד…)",
                created_at: "",
              }}
              isStreaming
            />
          )}
          {streamError && (
            <div className="rounded-lg border border-danger/40 bg-danger-bg p-3 text-danger text-sm">
              {streamError}
            </div>
          )}
        </div>

        <div className="border-t border-rule pt-3 space-y-2">
          <Textarea
            value={draft}
            onChange={(e) => setDraft(e.target.value)}
            placeholder="שאל את הסוכן… (Shift+Enter לשורה חדשה)"
            rows={3} dir="rtl"
            disabled={streaming}
            onKeyDown={(e) => {
              if (e.key === "Enter" && !e.shiftKey) {
                e.preventDefault();
                void onSend();
              }
            }}
          />
          <div className="flex items-center gap-2">
            <p className="text-[0.72rem] text-ink-muted grow">
              {data.conversation.claude_session_id
                ? "שיחה ממשיכה (--resume) — אין צורך לטעון מחדש את ה-system prompt"
                : "שיחה חדשה — system prompt ייטען (שני מסמכי ייחוס + רשימת קורפוס)"}
            </p>
            <Button onClick={onSend} disabled={streaming || !draft.trim()}
              className="bg-navy text-parchment hover:bg-navy-soft">
              {streaming ? (
                <Loader2 className="w-4 h-4 animate-spin me-1" />
              ) : (
                <Send className="w-4 h-4 me-1" />
              )}
              שלח
            </Button>
          </div>
        </div>
      </CardContent>
    </Card>
  );
}

function MessageBubble({
  message, isStreaming = false,
}: { message: ChatMessage; isStreaming?: boolean }) {
  const isUser = message.role === "user";
  return (
    <div className={isUser ? "flex justify-start" : "flex justify-end"}>
      <div
        className={
          "max-w-[85%] rounded-lg px-3 py-2 text-sm leading-relaxed whitespace-pre-wrap " +
          (isUser
            ? "bg-gold-wash text-ink border border-gold/40"
            : "bg-rule-soft text-ink border border-rule")
        }
        dir="rtl"
      >
        {message.content}
        {isStreaming && (
          <span className="inline-block w-1.5 h-3.5 bg-navy/60 align-middle ms-1 animate-pulse" />
        )}
      </div>
    </div>
  );
}

// ── Service-down warning ──────────────────────────────────────────

function ChatServiceWarning({
  health,
}: { health: { reachable: boolean; url: string; error?: string } }) {
  return (
    <Card className="bg-danger-bg border-danger/40">
      <CardContent className="px-4 py-3 space-y-1">
        <div className="flex items-center gap-2 text-danger">
          <AlertTriangle className="w-4 h-4" />
          <strong>שירות הצ&apos;אט אינו זמין</strong>
        </div>
        <p className="text-[0.78rem] text-danger">
          לא ניתן להגיע ל-legal-chat-service בכתובת
          <code className="px-1 mx-1 bg-rule-soft rounded">{health.url}</code>.
          {health.error && (<> פירוט: <code className="px-1 bg-rule-soft rounded">{health.error}</code></>)}
        </p>
        <p className="text-[0.72rem] text-ink-muted">
          על המכונה המקומית הפעל:&nbsp;
          <code className="px-1 bg-rule-soft rounded">
            pm2 start /home/chaim/legal-ai/scripts/legal-chat-service.config.cjs
          </code>
        </p>
      </CardContent>
    </Card>
  );
}
