"use client";

import Link from "next/link";
import { useEffect, useMemo, useRef, useState } from "react";
import { ChevronLeft, Loader2, MessageCircle, Minus, Send, Star, TicketCheck, Wifi, WifiOff, X } from "lucide-react";
import { LIVECHAT_ENABLED_KEY, LIVECHAT_OPEN_EVENT, LIVECHAT_OPEN_KEY } from "@/components/livechat-open-button";
import { cn } from "@/lib/utils";

type SessionStatus = "loading" | "guest" | "authenticated";

type ChatMessage = {
  id: string;
  senderRole: "USER" | "ADMIN" | "SYSTEM";
  body: string;
  createdAt: string;
  sender?: {
    username: string;
  } | null;
};

type Conversation = {
  id: string;
  status: string;
  rating: number | null;
  ratingComment: string | null;
  ratingRequestedAt: string | null;
  messages: ChatMessage[];
};

type Availability = {
  liveChatOnline: boolean;
  message: string;
  supportHours: string;
  ticketResponseTime: string;
};

type LivechatPayload = {
  ok: boolean;
  data?: {
    availability: Availability;
    conversation: Conversation | null;
  };
  error?: {
    message?: string;
  };
};

type ConversationPayload = {
  ok: boolean;
  data?: {
    conversation: Conversation;
  };
  error?: {
    message?: string;
  };
};

export function SupportLiveChatWidget({ sessionStatus }: { sessionStatus: SessionStatus }) {
  const [enabled, setEnabled] = useState(false);
  const [open, setOpen] = useState(false);
  const [availability, setAvailability] = useState<Availability | null>(null);
  const [conversation, setConversation] = useState<Conversation | null>(null);
  const [draft, setDraft] = useState("");
  const [initialMessage, setInitialMessage] = useState("");
  const [rating, setRating] = useState(5);
  const [ratingComment, setRatingComment] = useState("");
  const [message, setMessage] = useState("");
  const [loading, setLoading] = useState(false);
  const [sending, setSending] = useState(false);
  const bottomRef = useRef<HTMLDivElement | null>(null);
  const ignoredClosedConversationIdRef = useRef<string | null>(null);

  const canRate = useMemo(
    () => Boolean(conversation && !conversation.rating && (conversation.ratingRequestedAt || conversation.status === "CLOSED")),
    [conversation]
  );
  const isClosed = conversation?.status === "CLOSED";
  const hasActiveConversation = Boolean(conversation && conversation.status !== "CLOSED");

  useEffect(() => {
    const storedEnabled = window.localStorage.getItem(LIVECHAT_ENABLED_KEY) === "1";
    const storedOpen = window.localStorage.getItem(LIVECHAT_OPEN_KEY) === "1";
    setEnabled(storedEnabled);
    setOpen(storedOpen);

    function openWidget() {
      window.localStorage.setItem(LIVECHAT_ENABLED_KEY, "1");
      window.localStorage.setItem(LIVECHAT_OPEN_KEY, "1");
      setEnabled(true);
      setOpen(true);
      if (sessionStatus === "authenticated") {
        void load({ keepClosedVisible: true });
      }
    }

    window.addEventListener(LIVECHAT_OPEN_EVENT, openWidget);
    return () => window.removeEventListener(LIVECHAT_OPEN_EVENT, openWidget);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [sessionStatus]);

  useEffect(() => {
    if (sessionStatus !== "authenticated" || !enabled) return;
    void load({ silent: Boolean(conversation) });
    const timer = window.setInterval(() => void load({ silent: true }), 5000);
    return () => window.clearInterval(timer);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [sessionStatus, enabled]);

  useEffect(() => {
    if (!open) return;
    bottomRef.current?.scrollIntoView({ block: "end" });
  }, [conversation?.messages.length, open]);

  useEffect(() => {
    if (conversation?.status !== "CLOSED" || open) return;
    clearWidgetState();
  }, [conversation?.status, open]);

  async function load(options: { silent?: boolean; keepClosedVisible?: boolean } = {}) {
    if (sessionStatus !== "authenticated") return;
    if (!options.silent) setLoading(true);
    const response = await fetch("/api/support/livechat", { cache: "no-store" });
    const payload = (await response.json()) as LivechatPayload;
    if (!options.silent) setLoading(false);

    if (!payload.ok || !payload.data) {
      if (!options.silent) setMessage(payload.error?.message ?? "Livechat indisponible pour le moment.");
      return;
    }

    const nextConversation = payload.data.conversation;
    const shouldIgnoreClosedConversation =
      nextConversation?.status === "CLOSED" && ignoredClosedConversationIdRef.current === nextConversation.id;

    setAvailability(payload.data.availability);
    setConversation(shouldIgnoreClosedConversation ? null : nextConversation);
    if (nextConversation && nextConversation.status !== "CLOSED") {
      ignoredClosedConversationIdRef.current = null;
    }
    if (shouldIgnoreClosedConversation) {
      return;
    }
    if (nextConversation?.status === "CLOSED" && !options.keepClosedVisible && !open) {
      clearWidgetState();
    }
  }

  function minimize() {
    setOpen(false);
    window.localStorage.setItem(LIVECHAT_OPEN_KEY, "0");
  }

  function clearWidgetState() {
    window.localStorage.removeItem(LIVECHAT_ENABLED_KEY);
    window.localStorage.removeItem(LIVECHAT_OPEN_KEY);
    ignoredClosedConversationIdRef.current = null;
    setEnabled(false);
    setOpen(false);
    setConversation(null);
  }

  function hideWhenClosed() {
    if (!isClosed) {
      minimize();
      return;
    }
    clearWidgetState();
  }

  function prepareNewChat() {
    if (conversation?.status === "CLOSED") {
      ignoredClosedConversationIdRef.current = conversation.id;
    }
    setConversation(null);
    setDraft("");
    setInitialMessage("");
    setRating(5);
    setRatingComment("");
    setMessage("");
  }

  async function startChat() {
    if (sessionStatus !== "authenticated") return;
    setSending(true);
    setMessage("");
    const response = await fetch("/api/support/livechat", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ message: initialMessage })
    });
    const payload = (await response.json()) as ConversationPayload;
    setSending(false);

    if (!payload.ok || !payload.data) {
      setMessage(payload.error?.message ?? "Ouverture du livechat impossible.");
      await load();
      return;
    }

    setInitialMessage("");
    ignoredClosedConversationIdRef.current = null;
    setConversation(payload.data.conversation);
  }

  async function sendMessage() {
    if (!conversation || !draft.trim()) return;
    setSending(true);
    const response = await fetch(`/api/support/livechat/${conversation.id}/messages`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ message: draft })
    });
    const payload = (await response.json()) as ConversationPayload;
    setSending(false);

    if (!payload.ok || !payload.data) {
      setMessage(payload.error?.message ?? "Message impossible.");
      return;
    }

    setDraft("");
    setConversation(payload.data.conversation);
  }

  async function closeConversation() {
    if (!conversation) return;
    setSending(true);
    const response = await fetch(`/api/support/livechat/${conversation.id}`, {
      method: "PATCH",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ action: "close" })
    });
    const payload = (await response.json()) as ConversationPayload;
    setSending(false);
    if (payload.ok && payload.data) {
      setConversation(payload.data.conversation);
    }
  }

  async function sendRating() {
    if (!conversation) return;
    setSending(true);
    const response = await fetch(`/api/support/livechat/${conversation.id}`, {
      method: "PATCH",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ action: "rate", rating, comment: ratingComment })
    });
    const payload = (await response.json()) as ConversationPayload;
    setSending(false);

    if (!payload.ok || !payload.data) {
      setMessage(payload.error?.message ?? "Notation impossible.");
      return;
    }

    setConversation(payload.data.conversation);
  }

  if (!enabled) {
    return null;
  }

  if (!open) {
    if (isClosed) {
      return null;
    }

    return (
      <button
        type="button"
        onClick={() => {
          setOpen(true);
          window.localStorage.setItem(LIVECHAT_OPEN_KEY, "1");
          if (sessionStatus === "authenticated") void load({ silent: true, keepClosedVisible: true });
        }}
        className="fixed bottom-[92px] right-4 z-[80] grid h-13 w-13 place-items-center rounded-full border border-felt/35 bg-felt text-ink-950 shadow-[0_16px_40px_rgba(0,0,0,.35)] lg:bottom-5 lg:h-14 lg:w-14"
        aria-label="Ouvrir le livechat"
      >
        <MessageCircle className="h-6 w-6" />
        {hasActiveConversation ? <span className="absolute right-1 top-1 h-3 w-3 rounded-full border-2 border-ink-950 bg-gold" /> : null}
      </button>
    );
  }

  return (
    <section className="fixed inset-0 z-[80] flex flex-col overflow-hidden bg-white text-slate-950 sm:inset-auto sm:bottom-5 sm:right-5 sm:h-[640px] sm:w-[390px] sm:rounded-2xl sm:shadow-[0_20px_70px_rgba(0,0,0,.5)]">
      <header className="flex min-h-16 items-center gap-3 border-b border-slate-200 px-4">
        <button type="button" onClick={minimize} className="grid h-9 w-9 place-items-center rounded-full text-slate-600 transition hover:bg-slate-100" aria-label="Réduire le livechat">
          <ChevronLeft className="h-5 w-5" />
        </button>
        <span className="grid h-8 w-8 shrink-0 place-items-center rounded-lg bg-felt text-sm font-black text-ink-950">Z</span>
        <div className="min-w-0 flex-1">
          <h2 className="truncate text-sm font-black text-slate-950">ZiraBet</h2>
          <p className="truncate text-xs font-medium text-slate-500">L'équipe peut également vous aider</p>
        </div>
        <button type="button" onClick={minimize} className="grid h-9 w-9 place-items-center rounded-full text-slate-500 transition hover:bg-slate-100" aria-label="Réduire">
          <Minus className="h-5 w-5" />
        </button>
        <button type="button" onClick={hideWhenClosed} className="grid h-9 w-9 place-items-center rounded-full text-slate-500 transition hover:bg-slate-100" aria-label={isClosed ? "Masquer le livechat" : "Fermer le panneau"}>
          <X className="h-5 w-5" />
        </button>
      </header>

      <div className="flex-1 overflow-y-auto px-4 py-4">
        {sessionStatus === "loading" ? <StateCard icon={Loader2} title="Connexion au support" body="Chargement de votre session..." loading /> : null}

        {sessionStatus === "guest" ? (
          <div className="space-y-3">
            <SupportBubble body="Connectez-vous pour ouvrir une conversation avec le support ZiraBet." />
            <Link href="/login" className="ml-auto grid h-11 w-fit place-items-center rounded-full bg-felt px-5 text-sm font-black text-ink-950">
              Connexion
            </Link>
          </div>
        ) : null}

        {sessionStatus === "authenticated" && loading ? (
          <StateCard icon={Loader2} title="Livechat" body="Ouverture de votre espace support..." loading />
        ) : null}

        {sessionStatus === "authenticated" && !loading ? (
          <>
            <div className="mb-4 flex items-center gap-2 rounded-2xl bg-slate-100 px-3 py-2 text-xs font-bold text-slate-600">
              {availability?.liveChatOnline ? <Wifi className="h-4 w-4 text-felt" /> : <WifiOff className="h-4 w-4 text-ember" />}
              {availability?.message ?? "Support ZiraBet"}
            </div>

            {message ? <div className="mb-3 rounded-2xl bg-red-50 px-3 py-2 text-xs font-bold text-red-600">{message}</div> : null}

            {conversation?.status === "OPEN" && availability && !availability.liveChatOnline ? (
              <div className="mb-3 rounded-2xl border border-amber-200 bg-amber-50 px-3 py-3 text-xs font-semibold leading-5 text-amber-800">
                <div className="flex items-start gap-2">
                  <WifiOff className="mt-0.5 h-4 w-4 shrink-0" />
                  <div className="min-w-0">
                    <p className="font-black">Le support vient de passer hors ligne.</p>
                    <p className="mt-1">{availability.ticketResponseTime}. Vous pouvez ouvrir un ticket pour conserver le suivi de votre demande.</p>
                    <Link
                      href="/support/tickets"
                      onClick={clearWidgetState}
                      className="mt-2 inline-flex h-8 items-center gap-2 rounded-full bg-felt px-3 text-[11px] font-black text-ink-950"
                    >
                      <TicketCheck className="h-3.5 w-3.5" />
                      Créer un ticket
                    </Link>
                  </div>
                </div>
              </div>
            ) : null}

            {!conversation && availability?.liveChatOnline ? (
              <div className="space-y-3">
                <SupportBubble body="Bonjour ! Comment pouvons-nous vous aider ?" />
                <div className="rounded-2xl border border-slate-200 bg-white p-3 shadow-sm">
                  <textarea
                    value={initialMessage}
                    onChange={(event) => setInitialMessage(event.target.value)}
                    className="min-h-20 w-full resize-none border-0 bg-transparent p-0 text-sm text-slate-900 placeholder:text-slate-400 focus:ring-0"
                    placeholder="Écrivez votre message..."
                  />
                  <button
                    type="button"
                    onClick={() => void startChat()}
                    disabled={sending}
                    className="mt-3 ml-auto flex h-9 items-center gap-2 rounded-full bg-felt px-4 text-xs font-black text-ink-950 disabled:opacity-50"
                  >
                    {sending ? <Loader2 className="h-4 w-4 animate-spin" /> : <Send className="h-4 w-4" />}
                    Envoyer
                  </button>
                </div>
              </div>
            ) : null}

            {!conversation && availability && !availability.liveChatOnline ? (
              <div className="space-y-3">
                <SupportBubble body={`Le livechat est hors ligne. ${availability.ticketResponseTime}.`} />
                <Link
                  href="/support/tickets"
                  onClick={clearWidgetState}
                  className="ml-auto flex h-11 w-fit items-center gap-2 rounded-full bg-felt px-5 text-sm font-black text-ink-950"
                >
                  <TicketCheck className="h-4 w-4" />
                  Créer un ticket
                </Link>
              </div>
            ) : null}

            {conversation ? (
              <div className="space-y-3">
                {conversation.messages.length === 0 ? <SupportBubble body="Bonjour ! Décrivez votre demande, un conseiller prendra le relais." /> : null}
                {conversation.messages.map((chatMessage) => (
                  <ChatBubble key={chatMessage.id} message={chatMessage} />
                ))}
                {conversation.status === "OPEN" ? (
                  <button
                    type="button"
                    onClick={() => void closeConversation()}
                    disabled={sending}
                    className="mx-auto flex h-8 items-center rounded-full bg-slate-100 px-3 text-[11px] font-bold text-slate-500 disabled:opacity-50"
                  >
                    Fermer la discussion
                  </button>
                ) : (
                  <div className="border-t border-slate-200 pt-3 text-center text-sm font-semibold text-slate-500">
                    <p>Votre conversation est terminée.</p>
                    {availability?.liveChatOnline ? (
                      <button
                        type="button"
                        onClick={prepareNewChat}
                        className="mt-3 inline-flex h-9 items-center gap-2 rounded-full bg-felt px-4 text-xs font-black text-ink-950"
                      >
                        <MessageCircle className="h-4 w-4" />
                        Ouvrir un nouveau chat
                      </button>
                    ) : (
                      <Link
                        href="/support/tickets"
                        onClick={clearWidgetState}
                        className="mt-3 inline-flex h-9 items-center gap-2 rounded-full bg-felt px-4 text-xs font-black text-ink-950"
                      >
                        <TicketCheck className="h-4 w-4" />
                        Créer un ticket
                      </Link>
                    )}
                  </div>
                )}
                {canRate ? (
                  <div className="rounded-2xl border border-slate-200 bg-slate-50 p-3">
                    <h3 className="text-sm font-black text-slate-950">Notez cette discussion</h3>
                    <div className="mt-2 flex gap-1">
                      {[1, 2, 3, 4, 5].map((value) => (
                        <button key={value} type="button" onClick={() => setRating(value)} className="text-amber-400">
                          <Star className={cn("h-6 w-6", value <= rating && "fill-amber-400")} />
                        </button>
                      ))}
                    </div>
                    <textarea
                      value={ratingComment}
                      onChange={(event) => setRatingComment(event.target.value)}
                      className="mt-2 min-h-16 w-full resize-none rounded-xl border border-slate-200 bg-white text-sm"
                      placeholder="Votre avis..."
                    />
                    <button type="button" onClick={() => void sendRating()} disabled={sending} className="mt-2 h-9 w-full rounded-full bg-felt text-xs font-black text-ink-950 disabled:opacity-50">
                      Envoyer mon avis
                    </button>
                  </div>
                ) : null}
              </div>
            ) : null}
          </>
        ) : null}
        <div ref={bottomRef} />
      </div>

      {conversation?.status === "OPEN" ? (
        <footer className="border-t border-slate-200 bg-white p-3">
          <div className="flex items-end gap-2 rounded-2xl border border-slate-200 bg-white px-3 py-2 shadow-sm">
            <textarea
              value={draft}
              onChange={(event) => setDraft(event.target.value)}
              onKeyDown={(event) => {
                if (event.key === "Enter" && !event.shiftKey) {
                  event.preventDefault();
                  void sendMessage();
                }
              }}
              className="max-h-28 min-h-10 flex-1 resize-none border-0 p-0 text-sm text-slate-900 placeholder:text-slate-400 focus:ring-0"
              placeholder="Envoyer un message..."
            />
            <button
              type="button"
              onClick={() => void sendMessage()}
              disabled={sending || !draft.trim()}
              className="grid h-10 w-10 shrink-0 place-items-center rounded-full bg-felt text-ink-950 disabled:bg-slate-200 disabled:text-slate-400"
              aria-label="Envoyer"
            >
              {sending ? <Loader2 className="h-4 w-4 animate-spin" /> : <Send className="h-4 w-4" />}
            </button>
          </div>
        </footer>
      ) : null}
    </section>
  );
}

function SupportBubble({ body }: { body: string }) {
  return (
    <div className="max-w-[82%] rounded-[22px] rounded-tl-md bg-slate-100 px-4 py-3 text-sm font-medium leading-5 text-slate-900">
      {body}
    </div>
  );
}

function ChatBubble({ message }: { message: ChatMessage }) {
  const isUser = message.senderRole === "USER";
  const label = isUser ? "Vous" : message.sender?.username ?? "Support";
  return (
    <div className={cn("max-w-[84%]", isUser && "ml-auto")}>
      <div
        className={cn(
          "rounded-[22px] px-4 py-3 text-sm font-medium leading-5",
          isUser ? "rounded-tr-md bg-felt text-ink-950" : "rounded-tl-md bg-slate-100 text-slate-900"
        )}
      >
        <p className="whitespace-pre-wrap">{message.body}</p>
      </div>
      <p className={cn("mt-1 text-[11px] font-medium text-slate-400", isUser && "text-right")}>
        {label} · {formatTime(message.createdAt)}
      </p>
    </div>
  );
}

function StateCard({ icon: Icon, title, body, loading = false }: { icon: typeof Loader2; title: string; body: string; loading?: boolean }) {
  return (
    <div className="rounded-2xl bg-slate-100 p-4 text-slate-700">
      <Icon className={cn("h-5 w-5 text-felt", loading && "animate-spin")} />
      <h3 className="mt-2 text-sm font-black text-slate-950">{title}</h3>
      <p className="mt-1 text-xs leading-5 text-slate-500">{body}</p>
    </div>
  );
}

function formatTime(value: string) {
  return new Intl.DateTimeFormat("fr-FR", { hour: "2-digit", minute: "2-digit" }).format(new Date(value));
}
