'use client';

import { Fragment, useEffect, useId, useRef, useState, type FormEvent, type ReactNode } from 'react';
import Link from 'next/link';
import { ARCHIE_GREETING, STARTER_SUGGESTIONS, type ArchieLink, type ArchieReply } from '@/lib/archie-shared';
import { LAST_RESULT_KEY, safeStorage } from '@/lib/storage';

interface Message extends Partial<ArchieReply> {
  id: number;
  from: 'archie' | 'visitor';
  text: string;
}

// Non-breaking spaces around the bullets: SVG drops the trailing ordinary space where the ring joins.
const RING_TEXT = 'SPEAK TO ARCHIE • SPEAK TO ARCHIE • ';
// Circumference of the r=47 text path, so the two repeats meet seamlessly.
const RING_LENGTH = 2 * Math.PI * 47;

/** Renders **bold** inline. */
function inline(text: string): ReactNode[] {
  return text.split(/(\*\*[^*]+\*\*)/g).map((part, i) =>
    part.startsWith('**') && part.endsWith('**') ? <strong key={i}>{part.slice(2, -2)}</strong> : <Fragment key={i}>{part}</Fragment>,
  );
}

/** Lines starting with "- " become a list; other lines become paragraphs. */
function RichText({ text }: { text: string }) {
  const blocks: ReactNode[] = [];
  let bullets: string[] = [];
  const flush = () => {
    if (bullets.length) {
      blocks.push(
        <ul key={`ul-${blocks.length}`}>
          {bullets.map((b, i) => (
            <li key={i}>{inline(b)}</li>
          ))}
        </ul>,
      );
      bullets = [];
    }
  };
  for (const line of text.split('\n')) {
    if (line.startsWith('- ')) {
      bullets.push(line.slice(2));
    } else {
      flush();
      if (line.trim()) blocks.push(<p key={`p-${blocks.length}`}>{inline(line)}</p>);
    }
  }
  flush();
  return <>{blocks}</>;
}

/** A woman's silhouette wearing a headset, sized for the 120×120 pod. */
function ArchieFigure() {
  return (
    <g>
      <path
        fill="#fff"
        d="M47.5 56c-1.6-12 4.4-20.5 12.5-20.5S74 44 72.5 56c-.4 3.6.6 8 4.5 12.2-4.2 1.3-8.3.2-10.7-2.4L66 66v4.2c7.6 1.2 15 5.8 17.4 14.8l1.6 7H35l1.6-7C39 76 46.4 71.4 54 70.2V66l-.3-.2c-2.4 2.6-6.5 3.7-10.7 2.4 3.9-4.2 4.9-8.6 4.5-12.2Z"
      />
      <path d="M45 54c0-12 6.6-18.5 15-18.5S75 42 75 54" fill="none" stroke="#14213d" strokeWidth="3" strokeLinecap="round" />
      <rect x="41.5" y="50" width="7.5" height="12" rx="3.5" fill="#14213d" />
      <rect x="71" y="50" width="7.5" height="12" rx="3.5" fill="#14213d" />
      <path d="M45 61.5c0 6 4 9 10 9" fill="none" stroke="#14213d" strokeWidth="2.2" strokeLinecap="round" />
      <circle cx="56.5" cy="70.5" r="2.4" fill="#14213d" />
    </g>
  );
}

const freshConversation = (): Message[] => [
  { id: 0, from: 'archie', text: ARCHIE_GREETING, suggestions: STARTER_SUGGESTIONS },
];

export function ArchieChat() {
  const [open, setOpen] = useState(false);
  const [messages, setMessages] = useState<Message[]>(freshConversation);
  const [draft, setDraft] = useState('');
  const [pending, setPending] = useState(false);
  const nextId = useRef(1);
  // Bumped on every reset, so a reply that arrives after a reset is dropped instead of reappearing.
  const conversation = useRef(0);
  const podRef = useRef<HTMLButtonElement>(null);
  const inputRef = useRef<HTMLInputElement>(null);
  const logRef = useRef<HTMLDivElement>(null);
  const panelId = useId();
  const ringId = `${useId().replace(/:/g, '')}-ring`;

  useEffect(() => {
    const root = document.documentElement;
    if (open) {
      root.dataset.archieOpen = 'true';
      inputRef.current?.focus();
    } else {
      delete root.dataset.archieOpen;
    }
    if (!open) return;
    const onKey = (e: KeyboardEvent) => {
      if (e.key === 'Escape') {
        close();
        podRef.current?.focus();
      }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [open]);

  /** Back to the greeting and starter questions, exactly as when Archie is first opened. */
  function reset() {
    conversation.current += 1;
    setMessages(freshConversation());
    setDraft('');
    setPending(false);
  }

  /** Closing always ends the conversation; the next open starts fresh. */
  function close() {
    reset();
    setOpen(false);
  }

  useEffect(() => {
    logRef.current?.scrollTo({ top: logRef.current.scrollHeight, behavior: 'smooth' });
  }, [messages, pending, open]);

  async function ask(question: string) {
    const text = question.trim();
    if (!text || pending) return;
    const thisConversation = conversation.current;
    setMessages((m) => [...m, { id: nextId.current++, from: 'visitor', text }]);
    setDraft('');
    setPending(true);
    let resultCode: string | undefined;
    try {
      resultCode = safeStorage()?.getItem(LAST_RESULT_KEY) ?? undefined;
    } catch {}
    try {
      const res = await fetch('/api/archie', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ message: text, resultCode }),
      });
      const body = (await res.json().catch(() => null)) as { reply?: ArchieReply; error?: string } | null;
      if (!res.ok || !body?.reply) throw new Error(body?.error ?? 'error');
      const reply = body.reply;
      if (conversation.current !== thisConversation) return;
      setMessages((m) => [...m, { id: nextId.current++, from: 'archie', ...reply }]);
    } catch (err) {
      if (conversation.current !== thisConversation) return;
      const text =
        err instanceof Error && err.message !== 'error'
          ? err.message
          : "Sorry, I couldn't answer just now. Please try again in a moment.";
      setMessages((m) => [...m, { id: nextId.current++, from: 'archie', text }]);
    } finally {
      if (conversation.current === thisConversation) {
        setPending(false);
        inputRef.current?.focus();
      }
    }
  }

  function onSubmit(e: FormEvent<HTMLFormElement>) {
    e.preventDefault();
    void ask(draft);
  }

  function onLink(link: ArchieLink) {
    // On small screens the panel covers the page, so get out of the way after navigating.
    if (!link.href.startsWith('mailto:') && window.matchMedia('(max-width: 639px)').matches) close();
  }

  const latestArchie = [...messages].reverse().find((m) => m.from === 'archie');

  return (
    <div className="archie no-print">
      {open && (
        <section id={panelId} className="archie-panel" role="dialog" aria-label="Chat with Archie">
          <header className="archie-head">
            <span className="archie-avatar" aria-hidden="true">
              <svg viewBox="30 30 60 60" width="40" height="40">
                <circle cx="60" cy="60" r="30" fill="url(#archie-core)" />
                <ArchieFigure />
              </svg>
            </span>
            <div>
              <strong>Archie</strong>
              <span>Your EntreJourneyMap guide</span>
            </div>
            <div className="archie-actions">
              <button
                type="button"
                className="archie-icon-btn"
                onClick={() => {
                  reset();
                  inputRef.current?.focus();
                }}
                aria-label="Start a new conversation"
                title="Start over"
              >
                <svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">
                  <path
                    d="M4.5 12a7.5 7.5 0 1 0 2.2-5.3M4.5 4v4h4"
                    fill="none"
                    stroke="currentColor"
                    strokeWidth="2"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                  />
                </svg>
              </button>
              <button
                type="button"
                className="archie-icon-btn"
                onClick={() => {
                  close();
                  podRef.current?.focus();
                }}
                aria-label="Close chat"
                title="Close"
              >
                <svg viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">
                  <path d="M6 6l12 12M18 6L6 18" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
                </svg>
              </button>
            </div>
          </header>

          <div className="archie-log" ref={logRef} aria-live="polite">
            {messages.map((m) => (
              <div key={m.id} className={`archie-msg from-${m.from}`}>
                <div className="archie-bubble">
                  {m.from === 'archie' ? <RichText text={m.text} /> : <p>{m.text}</p>}
                </div>
                {m.links && m.links.length > 0 && (
                  <div className="archie-links">
                    {m.links.map((l) =>
                      l.href.startsWith('mailto:') ? (
                        <a key={l.href} href={l.href} className="archie-link">
                          {l.label} →
                        </a>
                      ) : (
                        <Link key={l.href} href={l.href} className="archie-link" onClick={() => onLink(l)}>
                          {l.label} →
                        </Link>
                      ),
                    )}
                  </div>
                )}
              </div>
            ))}
            {pending && (
              <div className="archie-msg from-archie">
                <div className="archie-bubble archie-typing" aria-label="Archie is typing">
                  <span />
                  <span />
                  <span />
                </div>
              </div>
            )}
            {!pending && latestArchie?.suggestions && latestArchie.suggestions.length > 0 && (
              <div className="archie-suggestions" aria-label="Suggested questions">
                {latestArchie.suggestions.map((s) => (
                  <button key={s} type="button" className="archie-chip" onClick={() => void ask(s)}>
                    {s}
                  </button>
                ))}
              </div>
            )}
          </div>

          <form className="archie-form" onSubmit={onSubmit}>
            <label htmlFor={`${panelId}-input`} className="sr-only">
              Ask Archie a question
            </label>
            <input
              ref={inputRef}
              id={`${panelId}-input`}
              className="archie-input"
              value={draft}
              onChange={(e) => setDraft(e.target.value)}
              placeholder="Ask me anything about Archetypes…"
              maxLength={500}
              autoComplete="off"
            />
            <button type="submit" className="archie-send" disabled={!draft.trim() || pending} aria-label="Send">
              <svg viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">
                <path d="M4 12h15M13 6l6 6-6 6" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" />
              </svg>
            </button>
          </form>
        </section>
      )}

      <button
        ref={podRef}
        type="button"
        className={open ? 'archie-pod is-open' : 'archie-pod'}
        onClick={() => (open ? close() : setOpen(true))}
        aria-expanded={open}
        aria-controls={open ? panelId : undefined}
        aria-label={open ? 'Close chat with Archie' : 'Speak to Archie'}
      >
        <svg viewBox="0 0 120 120" aria-hidden="true">
          <defs>
            <path id={ringId} d="M60 60m-47 0a47 47 0 1 1 94 0a47 47 0 1 1-94 0" />
            <radialGradient id="archie-core" cx="35%" cy="30%" r="80%">
              <stop offset="0%" stopColor="#f39a63" />
              <stop offset="100%" stopColor="#c4531f" />
            </radialGradient>
            <clipPath id="archie-clip">
              <circle cx="60" cy="60" r="34" />
            </clipPath>
          </defs>
          <circle className="archie-pod-bg" cx="60" cy="60" r="59" />
          <g className="archie-ring">
            <text>
              <textPath href={`#${ringId}`} textLength={RING_LENGTH} lengthAdjust="spacing">
                {RING_TEXT}
              </textPath>
            </text>
          </g>
          <circle cx="60" cy="60" r="34" fill="url(#archie-core)" />
          <g clipPath="url(#archie-clip)" className="archie-face">
            <ArchieFigure />
          </g>
          <g className="archie-x">
            <path d="M50 50l20 20M70 50L50 70" stroke="#fff" strokeWidth="4" strokeLinecap="round" />
          </g>
        </svg>
      </button>
    </div>
  );
}
