import { useState, useCallback, useMemo } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { ChevronRight, ChevronLeft, Pencil, Check, Loader2 } from 'lucide-react';
import { cn } from '@/lib/utils';
import { trpc } from '@/lib/trpc';
import { useNotify } from '@/hooks/useNotify';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Card, CardContent } from '@/components/ui/card';
import { JOB_ROLES, INDUSTRIES, USE_CASES, TONES } from './onboardingOptions';
import type { UserProfile } from '../../../shared/api-types';

// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------

type Step =
  | 'welcome'
  | 'jobRole'
  | 'industry'
  | 'useCase'
  | 'tone'
  | 'language'
  | 'reviewing'
  | 'done';

const STEP_ORDER: Step[] = [
  'welcome',
  'jobRole',
  'industry',
  'useCase',
  'tone',
  'language',
  'reviewing',
];

interface OnboardingFlowProps {
  profile: UserProfile;
}

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

const spring = { type: 'spring' as const, stiffness: 400, damping: 32 };

function AIBubble({ children }: { children: React.ReactNode }) {
  return (
    <motion.div
      initial={{ opacity: 0, y: 12 }}
      animate={{ opacity: 1, y: 0 }}
      transition={spring}
      className="flex items-start gap-3"
    >
      <div className="flex size-8 shrink-0 items-center justify-center rounded-full bg-primary">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none" width="16" height="16">
          <path d="M32,4 L48,32 L16,32 Z" fill="#040404" opacity="0.85"/>
          <path d="M16,32 L48,32 L32,60 Z" fill="#040404"/>
          <line x1="16" y1="32" x2="48" y2="32" stroke="#040404" strokeWidth="0.5" opacity="0.12"/>
          <circle cx="32" cy="32" r="2.5" fill="#040404" opacity="0.18"/>
        </svg>
      </div>
      <div className="rounded-2xl bg-muted/60 backdrop-blur-md border border-border/30 px-5 py-3.5 max-w-[85%]">
        <div className="text-sm leading-relaxed">{children}</div>
      </div>
    </motion.div>
  );
}

function UserBubble({ text }: { text: string }) {
  return (
    <motion.div
      initial={{ opacity: 0, y: 8 }}
      animate={{ opacity: 1, y: 0 }}
      transition={spring}
      className="flex justify-end"
    >
      <div className="rounded-2xl bg-primary/10 border border-primary/20 px-4 py-2.5 max-w-[70%]">
        <p className="text-sm">{text}</p>
      </div>
    </motion.div>
  );
}

/** Toggle-chip for multi-select. */
function Chip({
  label,
  selected,
  onClick,
}: {
  label: string;
  selected: boolean;
  onClick: () => void;
}) {
  return (
    <Button
      variant={selected ? 'default' : 'outline'}
      size="sm"
      className="rounded-full"
      onClick={onClick}
    >
      {label}
    </Button>
  );
}

// ---------------------------------------------------------------------------
// Component
// ---------------------------------------------------------------------------

export function OnboardingFlow({ profile }: OnboardingFlowProps) {
  const [step, setStep] = useState<Step>('welcome');
  // answers stores comma-joined values per field (supports multi-select)
  const [answers, setAnswers] = useState<Record<string, string>>({});
  // per-step selected chip sets (for multi-select toggle UI)
  const [selected, setSelected] = useState<Record<string, Set<string>>>({});
  const [freeTexts, setFreeTexts] = useState<Record<string, string>>({});
  const [customInput, setCustomInput] = useState('');
  const [reviewValues, setReviewValues] = useState<Record<string, string>>({});
  const [editingField, setEditingField] = useState<string | null>(null);
  const [editBuffer, setEditBuffer] = useState('');
  const [normalizeError, setNormalizeError] = useState(false);
  const [saveError, setSaveError] = useState(false);

  const utils = trpc.useUtils();
  const { notify, notifyError } = useNotify();

  const normalizeMutation = trpc.auth.normalizeOnboarding.useMutation();
  const updateMemoryMutation = trpc.auth.updateMemory.useMutation();

  const displayName =
    [profile.name, profile.surname].filter(Boolean).join(' ') ||
    profile.email.split('@')[0];

  // -- Chip toggle --

  const toggleChip = useCallback((field: string, value: string) => {
    setSelected((prev) => {
      const set = new Set(prev[field] ?? []);
      if (set.has(value)) set.delete(value);
      else set.add(value);
      return { ...prev, [field]: set };
    });
  }, []);

  const isChipSelected = useCallback(
    (field: string, value: string) => selected[field]?.has(value) ?? false,
    [selected],
  );

  // -- Navigation helpers --

  const goNext = useCallback(() => {
    const idx = STEP_ORDER.indexOf(step);
    if (idx >= 0 && idx < STEP_ORDER.length - 1) {
      setCustomInput('');
      setStep(STEP_ORDER[idx + 1]);
    }
  }, [step]);

  const goBack = useCallback(() => {
    const idx = STEP_ORDER.indexOf(step);
    if (idx > 0) {
      setCustomInput('');
      setStep(STEP_ORDER[idx - 1]);
    }
  }, [step]);

  /** Commit selections for a field and advance. */
  const commitAndNext = useCallback(
    (field: string) => {
      const chips = selected[field];
      const chipValues = chips ? [...chips] : [];
      const custom = customInput.trim();

      // Merge chip selections + optional custom input
      const allValues = [...chipValues];
      if (custom && !allValues.includes(custom)) allValues.push(custom);

      if (allValues.length > 0) {
        const joined = allValues.join(', ');
        setAnswers((prev) => ({ ...prev, [field]: joined }));
        // Track free text if custom input was used
        if (custom) {
          setFreeTexts((prev) => ({ ...prev, [field]: joined }));
        }
      }
      setCustomInput('');
      goNext();
    },
    [selected, customInput, goNext],
  );

  const handleSkip = useCallback(() => {
    updateMemoryMutation.mutate(
      { memory: {}, markOnboarded: true },
      {
        onSuccess: () => void utils.auth.status.invalidate(),
      },
    );
  }, [updateMemoryMutation, utils]);

  /** Check if the current step has at least one selection. */
  const hasSelection = useCallback(
    (field: string) => {
      const chips = selected[field];
      return (chips && chips.size > 0) || customInput.trim().length > 0;
    },
    [selected, customInput],
  );

  // -- Reviewing step --

  const startReview = useCallback(async () => {
    setStep('reviewing');

    const chipAnswers = { ...answers };
    const freeTextAnswers: Record<string, string> = {};

    for (const [key, val] of Object.entries(freeTexts)) {
      if (val && answers[key] === val) {
        freeTextAnswers[key] = val;
      }
    }

    setReviewValues({ ...chipAnswers });

    if (Object.keys(freeTextAnswers).length > 0) {
      try {
        const normalized = await normalizeMutation.mutateAsync({
          inputs: freeTextAnswers,
        });
        setReviewValues((prev) => ({ ...prev, ...normalized }));
        setNormalizeError(false);
      } catch {
        setNormalizeError(true);
      }
    }
  }, [answers, freeTexts, normalizeMutation]);

  const handleSave = useCallback(() => {
    setSaveError(false);
    const memory = { ...reviewValues };
    const fullName = [profile.name, profile.surname].filter(Boolean).join(' ');
    if (fullName) memory.user_name = fullName;
    updateMemoryMutation.mutate(
      { memory, markOnboarded: true },
      {
        onSuccess: () => {
          notify('success', 'toast.onboarding.completed', { descriptionKey: 'toast.onboarding.completedDescription' });
          void utils.auth.status.invalidate();
        },
        onError: (err) => {
          setSaveError(true);
          notifyError('toast.onboarding.error', err);
        },
      },
    );
  }, [reviewValues, profile, updateMemoryMutation, utils, notify, notifyError]);

  const handleEditStart = useCallback(
    (key: string) => {
      setEditingField(key);
      setEditBuffer(reviewValues[key] ?? '');
    },
    [reviewValues],
  );

  const handleEditConfirm = useCallback(() => {
    if (editingField) {
      setReviewValues((prev) => ({ ...prev, [editingField]: editBuffer }));
      setEditingField(null);
      setEditBuffer('');
    }
  }, [editingField, editBuffer]);

  // -- Past answers --

  const fieldLabels: Record<string, string> = {
    job_role: 'Role',
    industry: 'Industry',
    primary_use_case: 'Use case',
    tone_preference: 'Tone',
    language: 'Language',
  };
  const fieldOrder = ['job_role', 'industry', 'primary_use_case', 'tone_preference', 'language'];

  const pastAnswers: { label: string; value: string }[] = [];
  for (const key of fieldOrder) {
    if (answers[key]) {
      pastAnswers.push({ label: fieldLabels[key], value: answers[key] });
    }
  }

  // -- Detected language (human-readable) --
  const detectedLang = useMemo(() => {
    const raw =
      profile.memory?.language ??
      (typeof navigator !== 'undefined' ? navigator.language : 'en');
    // If it already looks like a display name (not a locale code), return as-is
    if (raw.length > 5 || !raw.includes('-')) {
      // Could be 'English', 'Italiano', or a bare code like 'en'
      try {
        const display = new Intl.DisplayNames([raw], { type: 'language' });
        return display.of(raw) ?? raw;
      } catch {
        return raw;
      }
    }
    try {
      const display = new Intl.DisplayNames([raw], { type: 'language' });
      return display.of(raw) ?? raw;
    } catch {
      return raw;
    }
  }, [profile.memory?.language]);

  // -- Step index for progress indicator --
  const stepIdx = STEP_ORDER.indexOf(step);
  const showBack = stepIdx > 1; // show back from jobRole onwards (not on welcome)

  // -- Render --

  return (
    <div className="flex h-full w-full items-center justify-center bg-background">
      <div className="w-full max-w-xl px-6 py-10">
        {/* Progress dots */}
        {step !== 'welcome' && step !== 'done' && (
          <div className="flex justify-center gap-1.5 mb-6">
            {STEP_ORDER.slice(1, -1).map((s, i) => (
              <div
                key={s}
                className={cn(
                  'h-1.5 rounded-full transition-all duration-300',
                  i < stepIdx - 1
                    ? 'w-6 bg-primary'
                    : i === stepIdx - 1
                      ? 'w-6 bg-primary'
                      : 'w-1.5 bg-muted-foreground/20',
                )}
              />
            ))}
          </div>
        )}

        <AnimatePresence mode="wait">
          <motion.div
            key={step}
            initial={{ opacity: 0, y: 20 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -10 }}
            transition={spring}
            className="flex flex-col gap-4"
          >
            {/* Past answers (user bubbles) */}
            {step !== 'welcome' && step !== 'reviewing' && (
              <div className="flex flex-col gap-2 mb-2">
                {pastAnswers.map(({ label, value }) => (
                  <UserBubble key={label} text={`${label}: ${value}`} />
                ))}
              </div>
            )}

            {/* ── WELCOME ── */}
            {step === 'welcome' && (
              <>
                <AIBubble>
                  <p>
                    Hi <span className="font-medium">{displayName}</span>! I&apos;m
                    your AI assistant. Let me learn a few things about you so I can
                    help better.
                  </p>
                </AIBubble>
                <div className="flex justify-end mt-2">
                  <Button onClick={goNext} size="sm">
                    Let&apos;s go <ChevronRight size={14} className="ml-1" />
                  </Button>
                </div>
              </>
            )}

            {/* ── JOB ROLE ── */}
            {step === 'jobRole' && (
              <>
                <AIBubble>What&apos;s your role? Pick all that apply.</AIBubble>
                <div className="flex flex-wrap gap-2 pl-11">
                  {JOB_ROLES.map((role) => (
                    <Chip
                      key={role}
                      label={role}
                      selected={isChipSelected('job_role', role)}
                      onClick={() => toggleChip('job_role', role)}
                    />
                  ))}
                </div>
                <div className="flex gap-2 pl-11">
                  <Input
                    placeholder="Type your own…"
                    value={customInput}
                    onChange={(e) => setCustomInput(e.target.value)}
                    onKeyDown={(e) => {
                      if (e.key === 'Enter' && hasSelection('job_role')) {
                        commitAndNext('job_role');
                      }
                    }}
                    className="h-8 text-sm"
                  />
                </div>
                <StepNav
                  showBack={showBack}
                  onBack={goBack}
                  onNext={() => commitAndNext('job_role')}
                  canNext={hasSelection('job_role')}
                  onSkip={handleSkip}
                />
              </>
            )}

            {/* ── INDUSTRY ── */}
            {step === 'industry' && (
              <>
                <AIBubble>What industry do you work in? Pick all that apply.</AIBubble>
                <div className="flex flex-wrap gap-2 pl-11">
                  {INDUSTRIES.map((ind) => (
                    <Chip
                      key={ind}
                      label={ind}
                      selected={isChipSelected('industry', ind)}
                      onClick={() => toggleChip('industry', ind)}
                    />
                  ))}
                </div>
                <div className="flex gap-2 pl-11">
                  <Input
                    placeholder="Type your own…"
                    value={customInput}
                    onChange={(e) => setCustomInput(e.target.value)}
                    onKeyDown={(e) => {
                      if (e.key === 'Enter' && hasSelection('industry')) {
                        commitAndNext('industry');
                      }
                    }}
                    className="h-8 text-sm"
                  />
                </div>
                <StepNav
                  showBack={showBack}
                  onBack={goBack}
                  onNext={() => commitAndNext('industry')}
                  canNext={hasSelection('industry')}
                  onSkip={handleSkip}
                />
              </>
            )}

            {/* ── USE CASE ── */}
            {step === 'useCase' && (
              <>
                <AIBubble>How will you mainly use adiuvAI? Pick all that apply.</AIBubble>
                <div className="flex flex-wrap gap-2 pl-11">
                  {USE_CASES.map((uc) => (
                    <Chip
                      key={uc}
                      label={uc}
                      selected={isChipSelected('primary_use_case', uc)}
                      onClick={() => toggleChip('primary_use_case', uc)}
                    />
                  ))}
                </div>
                <StepNav
                  showBack={showBack}
                  onBack={goBack}
                  onNext={() => commitAndNext('primary_use_case')}
                  canNext={hasSelection('primary_use_case')}
                  onSkip={handleSkip}
                />
              </>
            )}

            {/* ── TONE ── */}
            {step === 'tone' && (
              <>
                <AIBubble>How should I talk to you? Pick all that apply.</AIBubble>
                <div className="flex flex-wrap gap-2 pl-11">
                  {TONES.map((t) => (
                    <Chip
                      key={t}
                      label={t}
                      selected={isChipSelected('tone_preference', t)}
                      onClick={() => toggleChip('tone_preference', t)}
                    />
                  ))}
                </div>
                <StepNav
                  showBack={showBack}
                  onBack={goBack}
                  onNext={() => commitAndNext('tone_preference')}
                  canNext={hasSelection('tone_preference')}
                  onSkip={handleSkip}
                />
              </>
            )}

            {/* ── LANGUAGE ── */}
            {step === 'language' && (
              <>
                <AIBubble>
                  I&apos;ll respond in <span className="font-medium">{detectedLang}</span>.
                  Want to change it?
                </AIBubble>
                <div className="flex flex-wrap gap-2 pl-11">
                  <Chip
                    label={`Keep ${detectedLang}`}
                    selected={isChipSelected('language', detectedLang)}
                    onClick={() => toggleChip('language', detectedLang)}
                  />
                </div>
                <div className="flex gap-2 pl-11">
                  <Input
                    placeholder="Type a language…"
                    value={customInput}
                    onChange={(e) => setCustomInput(e.target.value)}
                    onKeyDown={(e) => {
                      if (e.key === 'Enter' && hasSelection('language')) {
                        // Commit language, then go to review
                        const chips = selected.language;
                        const chipValues = chips ? [...chips] : [];
                        const custom = customInput.trim();
                        const allValues = [...chipValues];
                        if (custom && !allValues.includes(custom)) allValues.push(custom);
                        if (allValues.length > 0) {
                          const joined = allValues.join(', ');
                          setAnswers((prev) => ({ ...prev, language: joined }));
                          if (custom) setFreeTexts((prev) => ({ ...prev, language: joined }));
                        }
                        setCustomInput('');
                        void startReview();
                      }
                    }}
                    className="h-8 text-sm"
                  />
                </div>
                <StepNav
                  showBack={showBack}
                  onBack={goBack}
                  onNext={() => {
                    // Commit language, then go to review
                    const chips = selected.language;
                    const chipValues = chips ? [...chips] : [];
                    const custom = customInput.trim();
                    const allValues = [...chipValues];
                    if (custom && !allValues.includes(custom)) allValues.push(custom);
                    if (allValues.length > 0) {
                      const joined = allValues.join(', ');
                      setAnswers((prev) => ({ ...prev, language: joined }));
                      if (custom) setFreeTexts((prev) => ({ ...prev, language: joined }));
                    }
                    setCustomInput('');
                    void startReview();
                  }}
                  canNext={hasSelection('language')}
                  onSkip={handleSkip}
                  nextLabel="Review"
                />
              </>
            )}

            {/* ── REVIEWING ── */}
            {step === 'reviewing' && (
              <>
                <AIBubble>Here&apos;s what I&apos;ll remember about you.</AIBubble>

                {normalizeError && (
                  <motion.div
                    initial={{ opacity: 0 }}
                    animate={{ opacity: 1 }}
                    className="ml-11 rounded-lg border border-amber-500/30 bg-amber-500/10 px-4 py-2.5 text-xs text-amber-700 dark:text-amber-400"
                  >
                    Couldn&apos;t auto-tidy — review and save as-is.
                  </motion.div>
                )}

                <Card className="ml-11 rounded-xl">
                  <CardContent className="px-5 py-4 flex flex-col gap-3">
                    {fieldOrder.map((key) => {
                      const value = reviewValues[key];
                      if (!value) return null;
                      const original = freeTexts[key];
                      const wasTidied = original && original !== value;

                      return (
                        <div key={key} className="flex items-center gap-3">
                          <div className="flex-1 min-w-0">
                            <p className="text-xs text-muted-foreground">
                              {fieldLabels[key]}
                            </p>
                            {editingField === key ? (
                              <div className="flex items-center gap-1 mt-0.5">
                                <Input
                                  value={editBuffer}
                                  onChange={(e) => setEditBuffer(e.target.value)}
                                  onKeyDown={(e) => {
                                    if (e.key === 'Enter') handleEditConfirm();
                                    if (e.key === 'Escape') setEditingField(null);
                                  }}
                                  className="h-7 text-sm"
                                  autoFocus
                                />
                                <Button
                                  size="sm"
                                  variant="ghost"
                                  className="h-7 w-7 p-0"
                                  onClick={handleEditConfirm}
                                >
                                  <Check size={12} />
                                </Button>
                              </div>
                            ) : (
                              <>
                                <p className="text-sm font-medium">{value}</p>
                                {wasTidied && (
                                  <p className="text-xs text-muted-foreground/60 mt-0.5">
                                    auto-tidied from &ldquo;{original}&rdquo;
                                  </p>
                                )}
                              </>
                            )}
                          </div>
                          {editingField !== key && (
                            <Button
                              size="sm"
                              variant="ghost"
                              className="h-7 w-7 p-0 shrink-0"
                              onClick={() => handleEditStart(key)}
                            >
                              <Pencil size={12} />
                            </Button>
                          )}
                        </div>
                      );
                    })}
                  </CardContent>
                </Card>

                {normalizeMutation.isPending && (
                  <div className="ml-11 flex items-center gap-2 text-xs text-muted-foreground">
                    <Loader2 size={14} className="animate-spin" />
                    Tidying up…
                  </div>
                )}

                {saveError && (
                  <div className="ml-11 text-xs text-red-500">
                    Failed to save — please try again.
                  </div>
                )}

                <div className="flex items-center gap-3 ml-11 mt-2">
                  <Button
                    variant="ghost"
                    size="sm"
                    onClick={goBack}
                  >
                    <ChevronLeft size={14} className="mr-1" /> Back
                  </Button>
                  <Button
                    onClick={handleSave}
                    size="sm"
                    disabled={updateMemoryMutation.isPending}
                  >
                    {updateMemoryMutation.isPending ? (
                      <Loader2 size={14} className="animate-spin mr-1.5" />
                    ) : null}
                    Looks good — save
                  </Button>
                </div>
              </>
            )}
          </motion.div>
        </AnimatePresence>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Small sub-components
// ---------------------------------------------------------------------------

function StepNav({
  showBack,
  onBack,
  onNext,
  canNext,
  onSkip,
  nextLabel = 'Next',
}: {
  showBack: boolean;
  onBack: () => void;
  onNext: () => void;
  canNext: boolean;
  onSkip: () => void;
  nextLabel?: string;
}) {
  return (
    <div className="flex items-center gap-2 pl-11 mt-2">
      {showBack && (
        <Button variant="ghost" size="sm" onClick={onBack}>
          <ChevronLeft size={14} className="mr-1" /> Back
        </Button>
      )}
      <Button size="sm" onClick={onNext} disabled={!canNext}>
        {nextLabel} <ChevronRight size={14} className="ml-1" />
      </Button>
      <button
        onClick={onSkip}
        className="text-xs text-muted-foreground hover:text-foreground transition-colors ml-auto"
      >
        Skip setup
      </button>
    </div>
  );
}
