"use client";

import { useEffect, useRef } from "react";
import Image from "next/image";
import { AlertTriangle, RotateCcw, User } from "lucide-react";
import type { ChatCopy } from "@/lib/chat/i18n";
import type { ChatBotEntry, ChatEntry, ChatNoticeEntry, ChatSendError, OutgoingSend } from "@/lib/chat/types";
import BlockRenderer from "./blocks";
import { useChatBlocks } from "./ChatBlockContext";

function BotAvatar() {
  return (
    <span className="mt-0.5 inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-white shadow-sm">
      <Image src="/favicon.png" alt="" width={18} height={18} className="h-[18px] w-[18px] rounded-full" />
    </span>
  );
}

function noticeText(error: ChatSendError, copy: ChatCopy): string {
  switch (error.kind) {
    case "network":
      return copy.errorNetwork;
    case "rate_limited":
      // The hourly cap on enquiry/lead submits comes with a long retry_after;
      // the server's (localised) message reads better than "wait 3412 seconds".
      return error.retryAfter > 120 && error.message ? error.message : copy.errorRateLimited(error.retryAfter);
    case "validation":
      return error.message || copy.errorServer;
    case "in_progress":
      // Localised by the server ("still being processed, try again in a moment").
      return error.message || copy.errorServer;
    case "server":
      return copy.errorServer;
  }
}

function BotMessage({ entry }: { entry: ChatBotEntry }) {
  return (
    <div className="flex items-start gap-2">
      <BotAvatar />
      <div className="min-w-0 flex-1 space-y-2">
        {entry.blocks.map((block, i) => (
          <BlockRenderer
            key={`${entry.id}:${i}`}
            block={block}
            blockKey={`${entry.id}:${i}`}
            receivedAt={entry.at}
            source={entry.source}
            sourceFormKey={entry.sourceFormKey}
          />
        ))}
      </div>
    </div>
  );
}

function NoticeMessage({ entry, onRetry }: { entry: ChatNoticeEntry; onRetry: (send: OutgoingSend) => void }) {
  const { copy, busy, isFormSubmitted, isFormDismissed } = useChatBlocks();
  // A form that has since gone through (via its own Submit) or been closed must not be re-sent from here.
  const formKey = entry.retry?.formKey;
  const formClosed = !!formKey && (isFormSubmitted(formKey) || isFormDismissed(formKey));
  const retry = entry.retry && !formClosed ? entry.retry : null;
  return (
    <div className="flex items-start gap-2">
      <BotAvatar />
      <div className="max-w-[85%] rounded-2xl rounded-tl-sm bg-red-50 px-3 py-2 text-xs text-red-800 ring-1 ring-red-100">
        <p className="flex items-start gap-1.5">
          <AlertTriangle size={13} className="mt-0.5 shrink-0" aria-hidden />
          <span>{noticeText(entry.error, copy)}</span>
        </p>
        {retry ? (
          <button
            type="button"
            onClick={() => onRetry(retry)}
            disabled={busy}
            className="mt-1.5 inline-flex items-center gap-1 rounded-md bg-white px-2 py-1 text-[11px] font-semibold text-[#CC1414] ring-1 ring-red-200 hover:bg-red-100 disabled:cursor-not-allowed disabled:opacity-60"
          >
            <RotateCcw size={12} aria-hidden /> {copy.retry}
          </button>
        ) : null}
      </div>
    </div>
  );
}

function UserMessage({ text }: { text: string }) {
  return (
    <div className="flex items-start justify-end gap-2">
      <div className="max-w-[78%] whitespace-pre-line break-words rounded-2xl rounded-tr-sm bg-[#CC1414] px-3 py-2 text-xs leading-relaxed text-white shadow-sm">
        {text}
      </div>
      <span
        aria-hidden
        className="mt-0.5 inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-[#CC1414]/10 text-[#CC1414]"
      >
        <User size={14} />
      </span>
    </div>
  );
}

function TypingIndicator({ label }: { label: string }) {
  return (
    <div className="flex items-start gap-2">
      <BotAvatar />
      <div className="inline-flex items-center gap-1 rounded-2xl rounded-tl-sm bg-white px-3 py-3 shadow-sm">
        <span className="sr-only">{label}</span>
        {[0, 150, 300].map((delay) => (
          <span
            key={delay}
            aria-hidden
            className="h-1.5 w-1.5 animate-bounce rounded-full bg-[#CC1414]/60"
            style={{ animationDelay: `${delay}ms` }}
          />
        ))}
      </div>
    </div>
  );
}

type Props = {
  entries: ChatEntry[];
  pending: boolean;
  onRetry: (send: OutgoingSend) => void;
};

/**
 * The conversation. A `log` live region so screen readers announce new
 * messages as they are appended (and not the whole list on re-render).
 */
export default function MessageList({ entries, pending, onRetry }: Props) {
  const { copy } = useChatBlocks();
  const listRef = useRef<HTMLDivElement>(null);
  const lastRef = useRef<HTMLDivElement>(null);
  const lastId = entries.length ? entries[entries.length - 1].id : null;

  /* Follow the conversation. A tall card (order detail, enquiry form) is
     scrolled to its top rather than its bottom so it reads from the start. */
  useEffect(() => {
    const list = listRef.current;
    if (!list) return;
    const bottom = list.scrollHeight - list.clientHeight;
    const last = lastRef.current;
    const top = pending || !last ? bottom : Math.min(bottom, last.offsetTop - 12);
    list.scrollTo({ top: Math.max(0, top), behavior: "smooth" });
  }, [lastId, pending]);

  return (
    <div
      ref={listRef}
      role="log"
      aria-live="polite"
      aria-relevant="additions"
      aria-label="Biznie AI"
      aria-busy={pending}
      className="relative min-h-0 flex-1 space-y-3 overflow-y-auto overscroll-contain bg-red-50/40 px-3 py-3 sm:h-[min(28rem,calc(100dvh-13rem))] sm:flex-none"
    >
      {entries.map((entry, i) => (
        <div key={entry.id} ref={i === entries.length - 1 ? lastRef : undefined}>
          {entry.role === "user" ? (
            <UserMessage text={entry.text} />
          ) : entry.role === "bot" ? (
            <BotMessage entry={entry} />
          ) : (
            <NoticeMessage entry={entry} onRetry={onRetry} />
          )}
        </div>
      ))}
      {pending ? <TypingIndicator label={copy.typing} /> : null}
    </div>
  );
}
