'use client';

import { useCallback, useEffect, useRef, useState } from 'react';
import { useRouter } from 'next/navigation';
import { ArrowRight, Clock, Gift, ListChecks, Save } from 'lucide-react';
import { encodeAnswers } from '@/lib/code';
import { EMAIL_GATE_AT_QUESTION } from '@/lib/config';
import { isArchetypeId, type Answer, type ArchetypeId, type LikertOption, type Question } from '@/lib/types';
import { LAST_RESULT_KEY, PROGRESS_KEY, RESULT_SAVED_EVENT, safeStorage } from '@/lib/storage';
import { RETAKE_LABEL, useHasCompleted } from './AssessmentLink';
import { EmailGate } from './EmailGate';

interface SavedProgress {
  answers: (Answer | null)[];
  index: number;
  order: Record<string, ArchetypeId[]>;
  /** Only whether the email step was completed; the email itself is never saved. */
  gatePassed?: boolean;
}

const POSITION_KEYS = 'ABCDEFGH';
const ADVANCE_DELAY_MS = 220;

function shuffle<T>(items: T[]): T[] {
  const a = [...items];
  for (let i = a.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a;
}

/** Scenario options are shuffled once per attempt so position never hints at an archetype. */
function freshOrder(questions: Question[]): Record<string, ArchetypeId[]> {
  return Object.fromEntries(
    questions.flatMap((q) => (q.kind === 'scenario' ? [[q.id, shuffle(q.options.map((o) => o.archetype))]] : [])),
  );
}

function readProgress(questions: Question[]): SavedProgress | null {
  try {
    const raw = safeStorage()?.getItem(PROGRESS_KEY);
    if (!raw) return null;
    const saved = JSON.parse(raw) as SavedProgress;
    const answersOk =
      Array.isArray(saved.answers) &&
      saved.answers.length === questions.length &&
      saved.answers.every((a, i) =>
        a === null || (questions[i].kind === 'likert' ? typeof a === 'number' : isArchetypeId(a)),
      );
    const orderOk = questions.every(
      (q) => q.kind === 'likert' || saved.order?.[q.id]?.length === q.options.length,
    );
    return answersOk && orderOk && Number.isInteger(saved.index) ? saved : null;
  } catch {
    return null;
  }
}

export function Assessment({
  questions,
  scale,
  introImageSrc,
}: {
  questions: Question[];
  scale: LikertOption[];
  /** Photo shown beside the intro text before the assessment starts. */
  introImageSrc?: string;
}) {
  const router = useRouter();
  const [ready, setReady] = useState(false);
  const [started, setStarted] = useState(false);
  const [finishing, setFinishing] = useState(false);
  const [index, setIndex] = useState(0);
  const [answers, setAnswers] = useState<(Answer | null)[]>(() => questions.map(() => null));
  const [order, setOrder] = useState<Record<string, ArchetypeId[]>>({});
  const [gatePassed, setGatePassed] = useState(false);
  const hasCompleted = useHasCompleted();
  const advanceTimer = useRef<number | undefined>(undefined);
  const headingRef = useRef<HTMLHeadingElement>(null);

  const gateOpen = ready && started && !finishing && !gatePassed && index >= EMAIL_GATE_AT_QUESTION - 1;

  // Restore an unfinished attempt (client only, so server and client render the same first frame).
  useEffect(() => {
    const saved = readProgress(questions);
    if (saved && saved.answers.some((a) => a !== null)) {
      setAnswers(saved.answers);
      setIndex(Math.min(Math.max(saved.index, 0), questions.length - 1));
      setOrder(saved.order);
      setGatePassed(saved.gatePassed === true);
      setStarted(true);
    } else {
      setOrder(freshOrder(questions));
    }
    setReady(true);
    return () => window.clearTimeout(advanceTimer.current);
  }, [questions]);

  useEffect(() => {
    if (!ready || !started || finishing) return;
    try {
      safeStorage()?.setItem(
        PROGRESS_KEY,
        JSON.stringify({ answers, index, order, gatePassed } satisfies SavedProgress),
      );
    } catch {
      // Storage full or blocked: the assessment still works, it just won't resume.
    }
  }, [ready, started, finishing, answers, index, order, gatePassed]);

  useEffect(() => {
    if (started) headingRef.current?.focus({ preventScroll: true });
  }, [index, started]);

  const finish = useCallback(
    (final: (Answer | null)[]) => {
      setFinishing(true);
      const code = encodeAnswers(questions, final as Answer[]);
      try {
        safeStorage()?.removeItem(PROGRESS_KEY);
        safeStorage()?.setItem(LAST_RESULT_KEY, code);
      } catch {
        // Ignore: the result lives in the URL.
      }
      window.dispatchEvent(new Event(RESULT_SAVED_EVENT));
      // The VIP Ticket offer comes first; it links on to the free result.
      router.push(`/vip?c=${code}`);
    },
    [questions, router],
  );

  const choose = useCallback(
    (value: Answer) => {
      if (finishing || gateOpen) return;
      const next = [...answers];
      next[index] = value;
      setAnswers(next);
      window.clearTimeout(advanceTimer.current);
      advanceTimer.current = window.setTimeout(() => {
        const firstGap = next.findIndex((a) => a === null);
        if (firstGap === -1 && index === questions.length - 1) finish(next);
        else if (index < questions.length - 1) setIndex(index + 1);
        else setIndex(firstGap);
      }, ADVANCE_DELAY_MS);
    },
    [answers, index, questions.length, finish, finishing, gateOpen],
  );

  const back = useCallback(() => {
    window.clearTimeout(advanceTimer.current);
    setIndex((i) => Math.max(i - 1, 0));
  }, []);

  const restart = () => {
    window.clearTimeout(advanceTimer.current);
    try {
      safeStorage()?.removeItem(PROGRESS_KEY);
    } catch {}
    setAnswers(questions.map(() => null));
    setOrder(freshOrder(questions));
    setGatePassed(false);
    setIndex(0);
    setStarted(false);
  };

  const continueAfterEmail = (_email: string) => {
    // The email is deliberately not sent or saved anywhere yet. When lead capture is switched on,
    // post it to /api/leads here (with a consent checkbox in EmailGate).
    setGatePassed(true);
  };

  const question = questions[index];

  useEffect(() => {
    if (!started || finishing || gateOpen) return;
    const onKey = (e: KeyboardEvent) => {
      if (e.metaKey || e.ctrlKey || e.altKey) return;
      const target = e.target as HTMLElement | null;
      if (target && ['INPUT', 'TEXTAREA', 'SELECT'].includes(target.tagName)) return;
      if (question.kind === 'likert' && /^[1-5]$/.test(e.key)) {
        choose(Number(e.key));
      } else if (question.kind === 'scenario') {
        const pos = POSITION_KEYS.indexOf(e.key.toUpperCase());
        const ids = order[question.id];
        if (pos !== -1 && ids && pos < ids.length) choose(ids[pos]);
      }
      if (e.key === 'ArrowLeft') back();
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [started, finishing, gateOpen, question, order, choose, back]);

  if (!ready) {
    return (
      <div className="card quiz-card quiz-intro" aria-busy="true">
        <p className="muted quiz-intro-body">Loading the assessment…</p>
      </div>
    );
  }

  if (!started) {
    return (
      <div className="card card-raised quiz-card quiz-intro">
        {introImageSrc && (
          <div className="quiz-intro-media">
            <img src={introImageSrc} alt="" />
          </div>
        )}
        <div className="quiz-intro-body">
          <span className="eyebrow">The EntreJourneyMap assessment</span>
          <h1 style={{ fontSize: 'clamp(1.8rem, 4.5vw, 2.6rem)' }}>Discover how you naturally create value.</h1>
          <p className="lede">
            Answer for your natural first response, not the role you admire or the job you happen to be doing right
            now. There are no right answers. Most entrepreneurs blend several archetypes.
          </p>
          <div className="quiz-intro-list">
            <div className="stat">
              <ListChecks aria-hidden="true" />
              <div>
                <strong>{questions.length}</strong>
                <span>questions</span>
              </div>
            </div>
            <div className="stat">
              <Clock aria-hidden="true" />
              <div>
                <strong>~8 min</strong>
                <span>to complete</span>
              </div>
            </div>
            <div className="stat">
              <Gift aria-hidden="true" />
              <div>
                <strong>Free</strong>
                <span>result, no sign-up</span>
              </div>
            </div>
          </div>
          <button className="start-btn" onClick={() => setStarted(true)}>
            {hasCompleted ? RETAKE_LABEL : 'Start the assessment'}
            <span className="start-btn-icon" aria-hidden="true">
              <ArrowRight />
            </span>
          </button>
          <p className="small muted quiz-intro-note">
            <Save aria-hidden="true" />
            Your progress is saved on this device, so you can leave and come back.
          </p>
        </div>
      </div>
    );
  }

  const answered = answers.filter((a) => a !== null).length;
  const current = answers[index];
  const percent = Math.round((answered / questions.length) * 100);

  return (
    <div className="quiz-card">
      <div className="progress">
        <span>
          Question {index + 1} of {questions.length}
        </span>
        <div
          className="progress-track"
          role="progressbar"
          aria-label="Assessment progress"
          aria-valuemin={0}
          aria-valuemax={100}
          aria-valuenow={percent}
        >
          <div className="progress-bar" style={{ width: `${percent}%` }} />
        </div>
        <span>{percent}%</span>
      </div>

      <div className="card card-raised">
        <p className="q-kind">
          {question.kind === 'likert' ? 'How much does this sound like you?' : 'Choose the answer that fits you best'}
        </p>
        <h1 className="q-text" ref={headingRef} tabIndex={-1} id={`${question.id}-label`}>
          {question.text}
        </h1>

        {question.kind === 'likert' ? (
          <div className="likert" role="radiogroup" aria-labelledby={`${question.id}-label`}>
            {scale.map((option) => (
              <button
                key={option.value}
                type="button"
                role="radio"
                aria-checked={current === option.value}
                className="choice"
                onClick={() => choose(option.value)}
                disabled={finishing}
              >
                <span className="choice-key" aria-hidden="true">
                  {option.value}
                </span>
                {option.label}
              </button>
            ))}
          </div>
        ) : (
          <div className="scenario-options" role="radiogroup" aria-labelledby={`${question.id}-label`}>
            {(order[question.id] ?? []).map((id, pos) => {
              const option = question.options.find((o) => o.archetype === id)!;
              return (
                <button
                  key={id}
                  type="button"
                  role="radio"
                  aria-checked={current === id}
                  className="choice"
                  onClick={() => choose(id)}
                  disabled={finishing}
                >
                  <span className="choice-key" aria-hidden="true">
                    {POSITION_KEYS[pos]}
                  </span>
                  {option.text}
                </button>
              );
            })}
          </div>
        )}

        <div className="quiz-nav">
          <button type="button" className="btn btn-ghost" onClick={back} disabled={index === 0 || finishing}>
            ← Back
          </button>
          {finishing ? (
            <span className="muted" role="status">
              Mapping your profile…
            </span>
          ) : current !== null && index < questions.length - 1 ? (
            <button type="button" className="btn btn-secondary" onClick={() => setIndex(index + 1)}>
              Next →
            </button>
          ) : (
            <button type="button" className="btn btn-ghost" onClick={restart}>
              Start over
            </button>
          )}
        </div>
      </div>
      <p className="quiz-hint">
        Tip: use the keys {question.kind === 'likert' ? '1–5' : 'A–H'} to answer and ← to go back.
      </p>
      <EmailGate
        open={gateOpen}
        questionNumber={index + 1}
        total={questions.length}
        onContinue={continueAfterEmail}
      />
    </div>
  );
}
