"use client";

import { startTransition, useEffect, useState } from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import Image from "next/image";
import { AlertTriangle, ArrowUp, Coins, Lock, Sparkles } from "lucide-react";
import { toast } from "sonner";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import {
  ChatContainerContent,
  ChatContainerRoot,
  ChatContainerScrollAnchor,
} from "@/components/ui/chat-container";
import { Message, MessageContent } from "@/components/ui/message";
import { preloadMarkdown } from "@/components/ui/markdown-lazy";
import { onbellekliJsonGetir } from "@/lib/istek-cache";
import {
  PromptInput,
  PromptInputAction,
  PromptInputActions,
  PromptInputTextarea,
} from "@/components/ui/prompt-input";
import { PromptSuggestion } from "@/components/ui/prompt-suggestion";
import { ScrollButton } from "@/components/ui/scroll-button";
import { DotsLoader } from "@/components/ui/loader";
import { Skeleton } from "@/components/ui/skeleton";
import { olay } from "@/lib/analitik";

export interface Mesaj {
  id: string;
  role: "user" | "assistant";
  content: string;
}

export interface DanismanOzeti {
  metin: string;
  uyarilar?: string[];
  kilitli?: boolean;
  /** Paketsizde açık uyarının ardından kilitli kalan uyarı sayısı. */
  kilitliUyariSayisi?: number;
}

/** Danışman mesajlarının avatarı — KolayTercih markası. */
function DanismanAvatar() {
  return (
    <span
      className="mt-0.5 flex size-8 shrink-0 items-center justify-center overflow-hidden rounded-full border border-slate-200 bg-white"
      aria-hidden
    >
      <Image
        src="/kolay-tercih-mark.svg"
        alt=""
        width={32}
        height={32}
        className="size-5"
      />
    </span>
  );
}

const ORNEK_SORULAR = [
  "Listemdeki kırmızı (riskli) tercihler ne kadar riskli?",
  "İlk 5 tercihimin taban sıralaması trendi nasıl?",
  "Güvenli dilimden bir tercihi daha üste alsam mantıklı mı?",
  "X bölümü ile Y bölümü arasında kalırsam neye bakmalıyım?",
];

/**
 * Listem sayfasındaki danışman sohbeti. /api/soru ile konuşur:
 * GET geçmiş + kredi, POST 1 kredi düşerek cevabı stream eder.
 */
export function SohbetClient({
  baslangicKredi,
  initialMesajlar,
  className,
  ozet,
}: {
  baslangicKredi: number;
  /** Sunucu tarafında çekilmiş geçmiş; verilirse mount fetch'i atlanır */
  initialMesajlar?: Mesaj[];
  /** Boyutlandırma override'ı (ör. alt popup'ta h-full) */
  className?: string;
  /** Raporun genel değerlendirmesi; sohbetin açılış mesajı olarak gösterilir */
  ozet?: DanismanOzeti;
}) {
  const [mesajlar, setMesajlar] = useState<Mesaj[]>(initialMesajlar ?? []);
  const [girdi, setGirdi] = useState("");
  const [bekliyor, setBekliyor] = useState(false);
  const [yuklendi, setYuklendi] = useState(initialMesajlar != null);
  const [kredi, setKredi] = useState(baslangicKredi);
  const router = useRouter();

  // Markdown chunk'ını sohbet görünür olur olmaz ısıt: ilk danışman cevabı
  // (veya geçmiş mesajlar) çizilirken lazy sınırında düz-metin flash'ı olmasın.
  useEffect(() => {
    void preloadMarkdown();
  }, []);

  useEffect(() => {
    // Geçmiş sunucudan geldiyse (listem sayfası) ekstra tur atma;
    // popup gibi geç mount olan yerlerde eski davranış sürer.
    if (initialMesajlar != null) return;
    // ttlMs: 0 = yalnız in-flight dedup — /sonuc popup'ı ile /listem aynı anda
    // mount olursa tek istek; kredi/geçmiş POST sonrası değiştiği için
    // TTL cache'i bilinçli kapalı.
    onbellekliJsonGetir<{ mesajlar?: Mesaj[]; kredi?: number }>("/api/soru", {
      ttlMs: 0,
    })
      .then((data) => {
        if (data?.mesajlar) setMesajlar(data.mesajlar);
        if (typeof data?.kredi === "number") setKredi(data.kredi);
      })
      .catch(() => {})
      .finally(() => setYuklendi(true));
  }, [initialMesajlar]);

  async function gonder(metin: string) {
    const mesaj = metin.trim();
    if (!mesaj || bekliyor) return;
    if (kredi < 1) {
      toast.error("Kredin bitti — devam etmek için kredi yükle.");
      return;
    }
    setGirdi("");
    setBekliyor(true);
    const clientMessageId = crypto.randomUUID();
    const asistanId = crypto.randomUUID();
    setMesajlar((m) => [
      ...m,
      { id: clientMessageId, role: "user", content: mesaj },
      { id: asistanId, role: "assistant", content: "" },
    ]);

    let birikmis = "";
    try {
      const res = await fetch("/api/soru", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ message: mesaj, clientMessageId }),
      });

      if (!res.ok) {
        const data = await res.json().catch(() => ({}));
        setMesajlar((m) =>
          m.filter((x) => x.id !== asistanId && x.id !== clientMessageId),
        );
        // Mesaj işlenmedi; kullanıcının yazdığı soru kaybolmasın
        setGirdi(mesaj);
        if (res.status === 402) {
          toast.error("Kredin bitti — kredi yükleyerek devam edebilirsin.");
          setKredi(0);
        } else {
          toast.error(data.error ?? "Bir sorun oluştu, tekrar dener misin?");
        }
        return;
      }

      setKredi((k) => k - 1);
      // Bu bileşen /sonuc'taki popup'tan da kullanılıyor (sohbet-popup.tsx)
      olay("danisman_sorusu", {
        sayfa: location.pathname.startsWith("/listem") ? "listem" : "sonuc",
      });
      const reader = res.body!.getReader();
      const decoder = new TextDecoder();
      for (;;) {
        const { done, value } = await reader.read();
        if (done) break;
        birikmis += decoder.decode(value, { stream: true });
        const anlik = birikmis;
        // Chunk başına gelen güncelleme acil değil: transition'a alınca
        // kullanıcı stream sürerken input'a takılmadan yazabilir
        startTransition(() =>
          setMesajlar((m) =>
            m.map((x) => (x.id === asistanId ? { ...x, content: anlik } : x)),
          ),
        );
      }
      // Header'daki kredi pill'i layout'ta server-render edilir ve client
      // harcamasını görmez; bakiye orada da güncellensin.
      router.refresh();
    } catch {
      // Sunucu hata anında krediyi iade edip yarım cevabı kaydetmiş olabilir;
      // tahmin etme: kayıtlı geçmişi ve bakiyeyi sunucudan çek (boş balon da
      // bu senkronla temizlenir). Senkron da düşerse boş balonu elle kaldır.
      try {
        const res = await fetch("/api/soru");
        const data = res.ok ? await res.json() : null;
        if (data?.mesajlar) setMesajlar(data.mesajlar);
        if (typeof data?.kredi === "number") setKredi(data.kredi);
      } catch {}
      if (!birikmis) {
        setMesajlar((m) => m.filter((x) => x.id !== asistanId));
        // Cevap hiç gelmedi; kullanıcının yazdığı soru kaybolmasın
        setGirdi(mesaj);
      }
      router.refresh();
      toast.error(
        birikmis
          ? "Bağlantı koptu — cevabın buraya kadar üretilen kısmı kaydedildi."
          : "Bağlantı koptu, cevap alınamadı. Kredin harcandıysa otomatik iade edildi.",
      );
    } finally {
      setBekliyor(false);
    }
  }

  const krediYok = kredi < 1;

  return (
    <section
      aria-label="Danışman sohbeti"
      className={cn(
        "flex flex-col overflow-hidden rounded-2xl border border-slate-200 bg-white",
        className ?? "h-[calc(100dvh-16rem)] min-h-[400px]",
      )}
    >
      <div className="flex items-center justify-between border-b border-slate-100 px-4 py-3">
        <h2 className="font-heading text-base font-bold">Danışmanla konuş</h2>
        <Link
          href="/paket"
          className="inline-flex items-center gap-1.5 rounded-full border border-amber-200 bg-amber-50 px-2.5 py-1 text-xs font-semibold text-amber-700 transition-colors hover:bg-amber-100"
          title="Kredilerin — yüklemek için tıkla"
        >
          <Coins className="size-3.5" aria-hidden />
          {kredi} kredi
        </Link>
      </div>

      <div className="relative flex-1 overflow-hidden">
        <ChatContainerRoot className="h-full">
          <ChatContainerContent className="gap-4 p-4">
            {ozet ? (
              <Message className="justify-start">
                <DanismanAvatar />
                <div className="flex max-w-[85%] flex-col gap-2">
                  <p className="text-xs font-semibold text-slate-500">
                    Danışman özeti
                  </p>
                  <MessageContent className="bg-slate-100 text-slate-800">
                    {ozet.metin}
                  </MessageContent>
                  {ozet.uyarilar?.length ? (
                    <ul className="flex flex-col gap-2">
                      {ozet.uyarilar.map((uyari) => (
                        <li
                          key={uyari}
                          className="flex items-start gap-2 rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-900"
                        >
                          <AlertTriangle
                            className="mt-0.5 size-4 shrink-0"
                            aria-hidden
                          />
                          {uyari}
                        </li>
                      ))}
                    </ul>
                  ) : null}
                  {ozet.kilitli ? (
                    <p className="flex items-center gap-1.5 text-xs text-slate-500">
                      <Lock className="size-3.5" aria-hidden />
                      {ozet.kilitliUyariSayisi ? (
                        <>
                          {ozet.kilitliUyariSayisi} uyarı daha kilitli —
                          sıralamana özel uyarıların pakette.
                        </>
                      ) : (
                        <>
                          Değerlendirmenin tamamı ve sıralamana özel uyarılar
                          pakette.
                        </>
                      )}
                    </p>
                  ) : null}
                </div>
              </Message>
            ) : null}
            {mesajlar.length === 0 ? (
              <div
                className={cn(
                  "flex flex-col gap-4",
                  !ozet && "items-center py-10 text-center",
                )}
              >
                {!ozet ? (
                  <>
                    <Sparkles
                      className="mx-auto size-7 text-primary"
                      aria-hidden
                    />
                    <div>
                      <p className="font-heading font-bold">
                        Listen hakkında her şeyi sorabilirsin
                      </p>
                      <p className="mx-auto mt-1 max-w-md text-sm text-slate-600">
                        Cevaplar senin 24&apos;lük listen, seçimlerin ve gerçek
                        YÖK Atlas verisi bağlamında üretilir. Her mesaj 1 kredi.
                      </p>
                    </div>
                  </>
                ) : null}
                {yuklendi ? (
                  <div
                    className={cn(
                      "flex max-w-lg flex-wrap gap-2",
                      !ozet && "justify-center",
                    )}
                  >
                    {ORNEK_SORULAR.map((s) => (
                      <PromptSuggestion
                        key={s}
                        size="sm"
                        className="cursor-pointer text-xs"
                        disabled={krediYok}
                        onClick={() => gonder(s)}
                      >
                        {s}
                      </PromptSuggestion>
                    ))}
                  </div>
                ) : (
                  <div
                    className={cn(
                      "flex max-w-lg flex-wrap gap-2",
                      !ozet && "justify-center",
                    )}
                  >
                    {[112, 148, 96, 132].map((w, i) => (
                      <Skeleton
                        key={i}
                        className="h-7 rounded-full"
                        style={{ width: w }}
                      />
                    ))}
                  </div>
                )}
              </div>
            ) : (
              mesajlar.map((m) =>
                m.role === "user" ? (
                  <Message key={m.id} className="justify-end">
                    <MessageContent className="max-w-[85%] bg-primary text-white">
                      {m.content}
                    </MessageContent>
                  </Message>
                ) : (
                  <Message key={m.id} className="justify-start">
                    <DanismanAvatar />
                    {m.content ? (
                      <MessageContent
                        markdown
                        className="max-w-[85%] bg-slate-100 text-slate-800 prose-sm"
                      >
                        {m.content}
                      </MessageContent>
                    ) : (
                      <div className="w-full max-w-[85%] space-y-2 rounded-lg bg-slate-100 px-4 py-3">
                        <Skeleton className="h-3.5 w-full bg-slate-200" />
                        <Skeleton className="h-3.5 w-4/5 bg-slate-200" />
                        <Skeleton className="h-3.5 w-3/5 bg-slate-200" />
                      </div>
                    )}
                  </Message>
                ),
              )
            )}
            <ChatContainerScrollAnchor />
          </ChatContainerContent>
          <div className="absolute bottom-4 right-4">
            <ScrollButton className="cursor-pointer bg-white shadow-md" />
          </div>
        </ChatContainerRoot>
      </div>

      <div className="border-t border-slate-100 p-3">
        {krediYok ? (
          <div className="flex flex-wrap items-center justify-between gap-3 rounded-2xl border border-amber-200 bg-amber-50 px-4 py-3">
            <p className="text-sm font-medium text-amber-800">
              Kredin bitti — sohbete devam etmek için kredi yükle.
            </p>
            <Button
              asChild
              size="sm"
              className="cursor-pointer bg-orange-500 text-white hover:bg-orange-600"
            >
              <Link href="/paket">Kredi yükle</Link>
            </Button>
          </div>
        ) : (
          <>
            {kredi <= 3 ? (
              <p className="mb-2 px-1 text-xs text-amber-700">
                Son {kredi} kredin — bitse de listen ve sohbetin kaybolmaz;{" "}
                <Link href="/paket" className="underline hover:text-amber-800">
                  kredi yükleyip
                </Link>{" "}
                kaldığın yerden devam edersin.
              </p>
            ) : null}
            <PromptInput
            value={girdi}
            onValueChange={setGirdi}
            onSubmit={() => gonder(girdi)}
            isLoading={bekliyor}
            disabled={bekliyor}
            maxHeight={160}
            className="rounded-2xl border-slate-200"
          >
            <PromptInputTextarea
              placeholder="Sorunu yaz… (1 kredi)"
              maxLength={2000}
            />
            <PromptInputActions className="justify-end pt-1">
              <PromptInputAction tooltip="Gönder (Enter)">
                <Button
                  size="icon"
                  onClick={() => gonder(girdi)}
                  disabled={bekliyor || !girdi.trim()}
                  className="size-9 cursor-pointer rounded-full bg-orange-500 text-white hover:bg-orange-600"
                  aria-label="Gönder"
                >
                  {bekliyor ? <DotsLoader size="sm" /> : <ArrowUp className="size-4" aria-hidden />}
                </Button>
              </PromptInputAction>
            </PromptInputActions>
          </PromptInput>
          </>
        )}
      </div>
    </section>
  );
}
