import { useEffect, useMemo, useRef, useState } from "react";
import { createFileRoute, useNavigate } from "@tanstack/react-router";
import { toast } from "sonner";
import { supabase } from "@/integrations/supabase/client";
import { useAuth } from "@/hooks/useAuth";
import { Wordmark } from "@/components/site-chrome";
import { Chip } from "@/components/chip";
import { fileToCompressedDataUrl, dataUrlToBlob } from "@/lib/images";
import { analyzeStyleProfile } from "@/lib/imisi.functions";
import { GENDERS, GOALS, PERCEPTIONS, stylesForGender, type StyleAnalysis } from "@/lib/imisi";

export const Route = createFileRoute("/onboarding")({
  head: () => ({
    meta: [
      { title: "Your Imisi style profile" },
      {
        name: "description",
        content: "A short conversation with Imisi so it can understand your body, colouring, goals and desired perception.",
      },
      { property: "og:title", content: "Your Imisi style profile" },
      { property: "og:description", content: "Build the style profile that powers every Imisi recommendation." },
    ],
  }),
  component: Onboarding,
});

const TOTAL = 7;

function Onboarding() {
  const navigate = useNavigate();
  const { session, loading } = useAuth();
  const [step, setStep] = useState(1);
  const [gender, setGender] = useState<string>("");
  const [name, setName] = useState("");
  const [frontData, setFrontData] = useState<string | null>(null);
  const [sideData, setSideData] = useState<string | null>(null);
  const [analysis, setAnalysis] = useState<StyleAnalysis | null>(null);
  const [analysing, setAnalysing] = useState(false);
  const [editing, setEditing] = useState(false);
  const [goals, setGoals] = useState<string[]>([]);
  const [perceptions, setPerceptions] = useState<string[]>([]);
  const [styles, setStyles] = useState<string[]>([]);
  const [discover, setDiscover] = useState(false);
  const [saving, setSaving] = useState(false);
  const bootstrapped = useRef(false);

  useEffect(() => {
    if (!loading && !session) navigate({ to: "/auth" });
  }, [loading, session, navigate]);

  useEffect(() => {
    if (!session || bootstrapped.current) return;
    bootstrapped.current = true;
    (async () => {
      const { data } = await supabase
        .from("profiles")
        .select("*")
        .eq("id", session.user.id)
        .maybeSingle();
      if (data?.onboarding_complete) {
        navigate({ to: "/style" });
        return;
      }
      if (data?.display_name) setName(data.display_name);
      if (data?.gender) setGender(data.gender);
    })();
  }, [session, navigate]);

  const styleOptions = useMemo(() => stylesForGender(gender), [gender]);

  const toggle = (list: string[], set: (v: string[]) => void, value: string, max?: number) => {
    if (list.includes(value)) set(list.filter((v) => v !== value));
    else if (!max || list.length < max) set([...list, value]);
  };

  const pickPhoto = async (file: File | undefined, which: "front" | "side") => {
    if (!file) return;
    try {
      const dataUrl = await fileToCompressedDataUrl(file);
      if (which === "front") setFrontData(dataUrl);
      else setSideData(dataUrl);
    } catch {
      toast.error("I couldn't read that image. Please try another photo.");
    }
  };

  const runAnalysis = async () => {
    if (!frontData || !session) return;
    setAnalysing(true);
    setStep(4);
    try {
      const uid = session.user.id;
      const uploads: Record<string, string> = {};
      const frontPath = `${uid}/front-${Date.now()}.jpg`;
      await supabase.storage.from("user-photos").upload(frontPath, dataUrlToBlob(frontData), {
        contentType: "image/jpeg",
        upsert: true,
      });
      uploads['photo_path'] = frontPath;
      if (sideData) {
        const sidePath = `${uid}/side-${Date.now()}.jpg`;
        await supabase.storage.from("user-photos").upload(sidePath, dataUrlToBlob(sideData), {
          contentType: "image/jpeg",
          upsert: true,
        });
        uploads['side_photo_path'] = sidePath;
      }
      await supabase
        .from("profiles")
        .update({ display_name: name || null, gender: gender || null, ...uploads })
        .eq("id", uid);

      const result = await analyzeStyleProfile({
        data: { frontImage: frontData, sideImage: sideData, gender, name },
      });
      setAnalysis(result);
    } catch (error) {
      toast.error(error instanceof Error ? error.message : "That analysis didn't complete.");
      setStep(3);
    } finally {
      setAnalysing(false);
    }
  };

  const finish = async () => {
    if (!session) return;
    setSaving(true);
    try {
      const { error } = await supabase
        .from("profiles")
        .update({
          display_name: name || null,
          gender: gender || null,
          goals,
          perceptions,
          styles: discover ? [] : styles,
          discover_style: discover,
          onboarding_complete: true,
        })
        .eq("id", session.user.id);
      if (error) throw error;
      if (analysis) {
        await supabase
          .from("style_profiles")
          .update({ ...analysis, confirmed: true })
          .eq("user_id", session.user.id);
      }
      navigate({ to: "/style" });
    } catch (error) {
      toast.error(error instanceof Error ? error.message : "Could not save your profile.");
    } finally {
      setSaving(false);
    }
  };

  const firstName = name.trim().split(" ")[0] || "there";

  return (
    <div className="min-h-screen bg-background">
      <div className="mx-auto flex h-16 max-w-3xl items-center justify-between px-5">
        <Wordmark />
        <span className="eyebrow">
          Step {Math.min(step, TOTAL)} of {TOTAL}
        </span>
      </div>
      <div className="mx-auto max-w-3xl px-5">
        <div className="h-px w-full bg-border">
          <div
            className="h-px bg-clay transition-all duration-500"
            style={{ width: `${(Math.min(step, TOTAL) / TOTAL) * 100}%` }}
          />
        </div>
      </div>

      <main className="mx-auto max-w-3xl px-5 py-12">
        {step === 1 && (
          <section key="s1" className="rise">
            <h1 className="text-4xl md:text-5xl">Who are we styling today?</h1>
            <p className="mt-3 text-sm text-muted-foreground">
              This helps Imisi understand silhouettes and styling language — nothing more.
            </p>
            <div className="mt-8 flex flex-wrap gap-3">
              {GENDERS.map((g) => (
                <Chip key={g} selected={gender === g} onClick={() => setGender(g)}>
                  {g}
                </Chip>
              ))}
            </div>
            <NextButton disabled={!gender} onClick={() => setStep(2)} />
          </section>
        )}

        {step === 2 && (
          <section key="s2" className="rise">
            <h1 className="text-4xl md:text-5xl">What should I call you?</h1>
            <p className="mt-3 text-sm text-muted-foreground">
              I'll use this name throughout our conversations.
            </p>
            <input
              value={name}
              onChange={(e) => setName(e.target.value)}
              placeholder="Ajoké"
              className="mt-8 w-full max-w-sm rounded-md border border-input bg-card px-4 py-3.5 text-lg outline-none focus:border-clay"
            />
            <NextButton disabled={!name.trim()} onClick={() => setStep(3)} label={`Continue as ${firstName}`} />
          </section>
        )}

        {step === 3 && (
          <section key="s3" className="rise">
            <h1 className="text-4xl md:text-5xl">Welcome, {firstName}. Let me see you.</h1>
            <p className="mt-3 text-sm text-muted-foreground">
              One clear, front-facing full-body photo. A side view is optional but helps me read your
              proportions more accurately. Your photos stay private to your account.
            </p>
            <div className="mt-8 grid gap-5 sm:grid-cols-2">
              <PhotoSlot
                label="Front-facing full body"
                required
                value={frontData}
                onPick={(f) => pickPhoto(f, "front")}
                onClear={() => setFrontData(null)}
              />
              <PhotoSlot
                label="Side view (optional)"
                value={sideData}
                onPick={(f) => pickPhoto(f, "side")}
                onClear={() => setSideData(null)}
              />
            </div>
            <NextButton disabled={!frontData} onClick={runAnalysis} label="Analyse my photo" />
          </section>
        )}

        {step === 4 && (
          <section key="s4" className="rise">
            {analysing || !analysis ? (
              <div className="py-16 text-center">
                <div className="mx-auto h-14 w-14 animate-spin rounded-full border-2 border-border border-t-clay" />
                <h1 className="mt-8 text-3xl">Reading your proportions and colouring…</h1>
                <p className="mt-3 text-sm text-muted-foreground">
                  I'm looking at your body shape, face shape, skin tone and undertone.
                </p>
              </div>
            ) : (
              <>
                <p className="eyebrow">Your style profile</p>
                <h1 className="mt-4 text-4xl">Did I get this right, {firstName}?</h1>
                <div className="paper mt-8 divide-y divide-border">
                  {(
                    [
                      ["Body shape", "body_shape"],
                      ["Face shape", "face_shape"],
                      ["Skin tone", "skin_tone"],
                      ["Undertone", "undertone"],
                      ["Body proportions", "proportions"],
                      ["Height", "height"],
                    ] as const
                  ).map(([label, key]) => (
                    <div key={key} className="flex flex-col gap-1 p-5 sm:flex-row sm:items-center sm:gap-6">
                      <span className="w-40 shrink-0 text-xs uppercase tracking-widest text-muted-foreground">
                        {label}
                      </span>
                      {editing ? (
                        <input
                          value={analysis[key]}
                          onChange={(e) => setAnalysis({ ...analysis, [key]: e.target.value })}
                          className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm outline-none focus:border-clay"
                        />
                      ) : (
                        <span className="text-sm">{analysis[key] || "—"}</span>
                      )}
                    </div>
                  ))}
                </div>
                {analysis.observations.length > 0 && (
                  <ul className="mt-6 space-y-2 text-sm text-muted-foreground">
                    {analysis.observations.map((o) => (
                      <li key={o} className="flex gap-2">
                        <span className="text-gold">◆</span>
                        {o}
                      </li>
                    ))}
                  </ul>
                )}
                <div className="mt-8 flex flex-wrap gap-3">
                  <button
                    onClick={() => setStep(5)}
                    className="rounded-md bg-clay px-7 py-3.5 text-sm font-medium text-clay-foreground"
                  >
                    Yes, that's me
                  </button>
                  <button
                    onClick={() => setEditing((v) => !v)}
                    className="rounded-md border border-input px-7 py-3.5 text-sm font-medium transition-colors hover:bg-secondary"
                  >
                    {editing ? "Done editing" : "Let me edit"}
                  </button>
                </div>
              </>
            )}
          </section>
        )}

        {step === 5 && (
          <section key="s5" className="rise">
            <h1 className="text-4xl md:text-5xl">What brings you to Imisi today?</h1>
            <p className="mt-3 text-sm text-muted-foreground">Choose as many as feel true.</p>
            <div className="mt-8 flex flex-wrap gap-3">
              {GOALS.map((g) => (
                <Chip key={g} selected={goals.includes(g)} onClick={() => toggle(goals, setGoals, g)}>
                  {g}
                </Chip>
              ))}
            </div>
            <NextButton disabled={goals.length === 0} onClick={() => setStep(6)} />
          </section>
        )}

        {step === 6 && (
          <section key="s6" className="rise">
            <h1 className="text-4xl md:text-5xl">How would you like to be perceived?</h1>
            <p className="mt-3 text-sm text-muted-foreground">Choose up to three.</p>
            <div className="mt-8 flex flex-wrap gap-3">
              {PERCEPTIONS.map((p) => (
                <Chip
                  key={p}
                  selected={perceptions.includes(p)}
                  disabled={perceptions.length >= 3}
                  onClick={() => toggle(perceptions, setPerceptions, p, 3)}
                >
                  {p}
                </Chip>
              ))}
            </div>
            <NextButton disabled={perceptions.length === 0} onClick={() => setStep(7)} />
          </section>
        )}

        {step === 7 && (
          <section key="s7" className="rise">
            <h1 className="text-4xl md:text-5xl">Which styles naturally appeal to you?</h1>
            <p className="mt-3 text-sm text-muted-foreground">
              Not sure yet? That's perfectly fine — I'll help you discover it.
            </p>
            <div className="mt-8 flex flex-wrap gap-3">
              {styleOptions.map((s) => (
                <Chip
                  key={s}
                  selected={!discover && styles.includes(s)}
                  onClick={() => {
                    setDiscover(false);
                    toggle(styles, setStyles, s);
                  }}
                >
                  {s}
                </Chip>
              ))}
            </div>
            <div className="mt-6">
              <Chip
                selected={discover}
                onClick={() => {
                  setDiscover(true);
                  setStyles([]);
                }}
              >
                Help me discover my style
              </Chip>
            </div>
            <NextButton
              disabled={(!discover && styles.length === 0) || saving}
              onClick={finish}
              label={saving ? "Saving your profile…" : "Complete my style profile"}
            />
          </section>
        )}
      </main>
    </div>
  );
}

function NextButton({
  disabled,
  onClick,
  label = "Continue",
}: {
  disabled?: boolean;
  onClick: () => void;
  label?: string;
}) {
  return (
    <button
      onClick={onClick}
      disabled={disabled}
      className="mt-10 rounded-md bg-clay px-8 py-3.5 text-sm font-medium text-clay-foreground transition-opacity hover:opacity-90 disabled:opacity-40"
    >
      {label}
    </button>
  );
}

function PhotoSlot({
  label,
  required,
  value,
  onPick,
  onClear,
}: {
  label: string;
  required?: boolean;
  value: string | null;
  onPick: (file: File | undefined) => void;
  onClear: () => void;
}) {
  return (
    <div className="paper overflow-hidden">
      {value ? (
        <div className="relative">
          <img src={value} alt={label} className="aspect-[3/4] w-full object-cover" />
          <button
            onClick={onClear}
            className="absolute right-3 top-3 rounded-md bg-background/90 px-3 py-1.5 text-xs"
          >
            Replace
          </button>
        </div>
      ) : (
        <label className="flex aspect-[3/4] cursor-pointer flex-col items-center justify-center gap-2 p-6 text-center">
          <span className="display text-3xl text-clay">+</span>
          <span className="text-sm">{label}</span>
          {required && <span className="text-xs text-muted-foreground">Required</span>}
          <input
            type="file"
            accept="image/*"
            className="hidden"
            onChange={(e) => onPick(e.target.files?.[0])}
          />
        </label>
      )}
    </div>
  );
}
