"use client";

import { useState, useRef, useEffect, useCallback } from "react";
import Link from "next/link";
import VillaLogo from "@/components/VillaLogo";
import VerificationStamp from "@/components/VerificationStamp";
import RealQRCode from "@/components/RealQRCode";
import { clientExecute, uploadFile } from "@/lib/api/client";
import { ApiError } from "@/lib/api/shared";

/** Convert a captured data: URL into a File so it can be uploaded via media.upload. */
async function dataUrlToFile(dataUrl: string, filename: string): Promise<File> {
  const res = await fetch(dataUrl);
  const blob = await res.blob();
  return new File([blob], filename, { type: blob.type || "image/jpeg" });
}

// ─── Types ────────────────────────────────────────────────────────────────────
type Step = "personal" | "identity" | "selfie" | "property-doc" | "review" | "submitted";

interface PersonalInfo {
  fullName: string; phone: string; dob: string;
  address: string; town: string; region: string;
  role: "landlord" | "agent";
}

interface DocSide {
  uploaded: boolean;
  fileName: string;
  dataUrl: string;
}

interface IdentityDoc {
  docType: string;
  docNumber: string;
  front: DocSide;
  back: DocSide;
}

interface SelfieData {
  captured: boolean;
  dataUrl: string;
}

interface PropertyDoc {
  docType: string;
  fileName: string;
  dataUrl: string;
  uploaded: boolean;
}

const REGIONS = [
  "Greater Accra","Eastern","Ashanti","Western","Central","Volta","Northern",
  "Upper East","Upper West","Bono","Bono East","Ahafo","Savannah","North East","Oti","Western North",
];

const DOC_TYPES = [
  "Ghana Card (National ID)",
  "Passport",
  "Voter's ID",
  "Driver's License",
  "SSNIT Card",
];

const STEPS: { id: Step; label: string }[] = [
  { id: "personal",     label: "Personal details" },
  { id: "identity",     label: "Identity document" },
  { id: "selfie",       label: "Selfie" },
  { id: "property-doc", label: "Property document" },
  { id: "review",       label: "Review & submit" },
];

const LANDLORD_PROPERTY_DOCS = [
  "Property title deed",
  "Land certificate",
  "Lease or tenancy agreement",
  "Purchase receipt",
  "Utility bill in property name",
  "Survey plan",
];

// ─── Shared primitives ────────────────────────────────────────────────────────
function FieldLabel({ children }: { children: React.ReactNode }) {
  return <label className="block font-mono text-xs uppercase tracking-widest text-ink-soft mb-2">{children}</label>;
}
function Input(props: React.InputHTMLAttributes<HTMLInputElement>) {
  return <input className="w-full border border-mist rounded-sm px-4 py-3 text-sm bg-white text-ink focus:outline-2 focus:outline-gold focus:border-forest" {...props} />;
}
function Select({ children, ...props }: React.SelectHTMLAttributes<HTMLSelectElement> & { children: React.ReactNode }) {
  return <select className="w-full border border-mist rounded-sm px-4 py-3 text-sm bg-white text-ink focus:outline-2 focus:outline-gold focus:border-forest" {...props}>{children}</select>;
}
function Btn({ children, onClick, variant = "primary", disabled = false, className = "" }: {
  children: React.ReactNode; onClick?: () => void;
  variant?: "primary" | "ghost"; disabled?: boolean; className?: string;
}) {
  const s = {
    primary: "bg-forest text-white hover:bg-forest-deep disabled:opacity-40",
    ghost: "border border-mist text-forest hover:bg-forest hover:border-forest hover:text-white",
  };
  return (
    <button type="button" onClick={onClick} disabled={disabled}
      className={`inline-flex items-center justify-center font-semibold text-sm px-6 py-3 rounded-pill transition-colors ${s[variant]} ${className}`}>
      {children}
    </button>
  );
}

// ─── Step progress bar ────────────────────────────────────────────────────────
function StepProgress({ current, role }: { current: Step; role: "landlord" | "agent" }) {
  const visibleSteps = role === "agent"
    ? STEPS.filter((s) => s.id !== "property-doc")
    : STEPS;
  const idx = visibleSteps.findIndex((s) => s.id === current);
  return (
    <div className="flex items-center gap-0 mb-8">
      {visibleSteps.map((s, i) => {
        const done = i < idx; const active = i === idx;
        return (
          <div key={s.id} className="flex items-center flex-1 last:flex-none">
            <div className="flex flex-col items-center gap-1.5">
              <div className={`w-8 h-8 rounded-full flex items-center justify-center text-xs font-bold transition-colors ${
                done ? "bg-forest text-white" : active ? "bg-gold text-forest-deep" : "bg-mist text-ink-soft"
              }`}>
                {done ? (
                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" className="w-4 h-4">
                    <path d="M5 12l5 5 9-11" strokeLinecap="round" strokeLinejoin="round" />
                  </svg>
                ) : i + 1}
              </div>
              <span className={`text-[10px] font-mono uppercase tracking-wider whitespace-nowrap hidden sm:block ${
                active ? "text-gold-deep font-semibold" : done ? "text-forest" : "text-ink-soft"
              }`}>{s.label}</span>
            </div>
            {i < STEPS.length - 1 && (
              <div className={`flex-1 h-0.5 mx-2 transition-colors ${done ? "bg-forest" : "bg-mist"}`} />
            )}
          </div>
        );
      })}
    </div>
  );
}


// ─── Camera capture widget (shared between ID sides and selfie) ───────────────
interface CameraWidgetProps {
  onCapture: (dataUrl: string) => void;
  onCancel: () => void;
  guideShape?: "rect" | "oval";
  facingModeDefault?: "user" | "environment";
  countdown?: boolean;
  label?: string;
}

function CameraWidget({ onCapture, onCancel, guideShape = "rect", facingModeDefault = "environment", countdown: withCountdown = false, label = "Capture photo" }: CameraWidgetProps) {
  const videoRef  = useRef<HTMLVideoElement>(null);
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const streamRef = useRef<MediaStream | null>(null);
  const [started,    setStarted]    = useState(false);
  const [camActive,  setCamActive]  = useState(false);
  const [camError,   setCamError]   = useState<string | null>(null);
  const [facingMode, setFacingMode] = useState(facingModeDefault);
  const [count,      setCount]      = useState(0);
  const [counting,   setCounting]   = useState(false);

  const stopStream = useCallback(() => {
    streamRef.current?.getTracks().forEach((t) => t.stop());
    streamRef.current = null;
    setCamActive(false);
  }, []);

  // Only clean up on unmount — no auto-start
  useEffect(() => {
    return () => stopStream();
  }, [stopStream]);

  async function startCam(facing: "user" | "environment") {
    setCamError(null);
    setCamActive(false);
    try {
      streamRef.current?.getTracks().forEach((t) => t.stop());
      const stream = await navigator.mediaDevices.getUserMedia({
        video: { facingMode: facing, width: { ideal: 1920 }, height: { ideal: 1080 } },
        audio: false,
      });
      streamRef.current = stream;
      if (videoRef.current) { videoRef.current.srcObject = stream; await videoRef.current.play(); }
      setCamActive(true);
    } catch (err: unknown) {
      const msg = err instanceof Error ? err.message : String(err);
      setCamError(
        msg.includes("Permission") || msg.includes("NotAllowed")
          ? "Camera access was denied. Please allow access in your browser settings."
          : msg.includes("NotFound") || msg.includes("DevicesNotFound")
          ? "No camera found on this device."
          : "Could not start camera. Please try again."
      );
    }
  }

  function flip() {
    const next = facingMode === "user" ? "environment" : "user";
    setFacingMode(next);
    startCam(next);
  }

  function doCapture() {
    const video = videoRef.current; const canvas = canvasRef.current;
    if (!video || !canvas) return;
    canvas.width = video.videoWidth || 1280;
    canvas.height = video.videoHeight || 720;
    const ctx = canvas.getContext("2d");
    if (!ctx) return;
    if (facingMode === "user") { ctx.translate(canvas.width, 0); ctx.scale(-1, 1); }
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
    const dataUrl = canvas.toDataURL("image/jpeg", 0.92);
    stopStream();
    onCapture(dataUrl);
  }

  function handleCapture() {
    if (!withCountdown) { doCapture(); return; }
    setCounting(true); setCount(3);
    let c = 3;
    const iv = setInterval(() => {
      c -= 1; setCount(c);
      if (c <= 0) { clearInterval(iv); setCounting(false); doCapture(); }
    }, 1000);
  }

  return (
    <div>
      {/* ── Idle — user hasn't tapped Open camera yet ── */}
      {!started && !camError && (
        <div>
          <div
            className="bg-ink rounded-lg overflow-hidden mb-3 flex flex-col items-center justify-center gap-4 text-white cursor-pointer hover:bg-ink/90 transition-colors"
            style={{ aspectRatio: guideShape === "oval" ? "4/3" : "16/10" }}
            onClick={() => { setStarted(true); startCam(facingMode); }}
          >
            <div className="w-16 h-16 rounded-full bg-white/10 flex items-center justify-center">
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" className="w-8 h-8">
                <path d="M23 19a2 2 0 01-2 2H3a2 2 0 01-2-2V8a2 2 0 012-2h4l2-3h6l2 3h4a2 2 0 012 2z" />
                <circle cx="12" cy="13" r="4" />
              </svg>
            </div>
            <div className="text-center">
              <p className="font-semibold text-sm">Camera is off</p>
              <p className="text-xs text-white/60 mt-1">Tap to open camera</p>
            </div>
          </div>
          <div className="flex gap-3">
            <button
              type="button"
              onClick={() => { setStarted(true); startCam(facingMode); }}
              className="flex-1 inline-flex items-center justify-center gap-2 font-semibold text-sm px-5 py-3 rounded-pill bg-forest text-white hover:bg-forest-deep transition-colors"
            >
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" className="w-4 h-4">
                <path d="M23 19a2 2 0 01-2 2H3a2 2 0 01-2-2V8a2 2 0 012-2h4l2-3h6l2 3h4a2 2 0 012 2z" /><circle cx="12" cy="13" r="4" />
              </svg>
              Open camera
            </button>
            <button
              type="button"
              onClick={onCancel}
              className="inline-flex items-center justify-center font-semibold text-sm px-4 py-3 rounded-pill border border-mist text-ink-soft hover:text-clay transition-colors"
            >
              Cancel
            </button>
          </div>
        </div>
      )}

      {/* ── Error ── */}
      {camError && (
        <div className="bg-[#F5EAE6] border border-clay rounded-md p-5 text-center">
          <p className="text-sm text-clay mb-3">{camError}</p>
          <div className="flex gap-3 justify-center">
            <button type="button" onClick={() => startCam(facingMode)} className="text-sm font-semibold text-forest hover:underline">Try again</button>
            <button type="button" onClick={onCancel} className="text-sm text-ink-soft hover:underline">Go back</button>
          </div>
        </div>
      )}

      {/* ── Live camera ── */}
      {started && !camError && (
        <div>
          <div className="bg-ink rounded-lg overflow-hidden mb-3 relative" style={{ aspectRatio: guideShape === "oval" ? "4/3" : "16/10" }}>
            <video ref={videoRef}
              className="w-full h-full object-cover"
              style={{ transform: facingMode === "user" ? "scaleX(-1)" : "none" }}
              playsInline muted />
            {camActive && !counting && (
              <div className="absolute inset-0 flex items-center justify-center pointer-events-none">
                {guideShape === "oval" ? (
                  <div className="border-2 border-white/50 border-dashed rounded-full"
                    style={{ width: "42%", height: "58%", marginTop: "-8%" }} />
                ) : (
                  <div className="relative border-2 border-white/60 border-dashed rounded-lg" style={{ width: "82%", height: "62%" }}>
                    <span className="absolute -top-6 left-0 right-0 flex justify-center">
                      <span className="text-white text-xs bg-black/50 px-3 py-0.5 rounded-pill">Position within frame</span>
                    </span>
                  </div>
                )}
              </div>
            )}
            {counting && (
              <div className="absolute inset-0 flex items-center justify-center bg-black/30">
                <div className="w-24 h-24 rounded-full bg-black/60 flex items-center justify-center">
                  <span className="text-white font-display font-bold text-5xl">{count}</span>
                </div>
              </div>
            )}
            {!camActive && !camError && (
              <div className="absolute inset-0 flex items-center justify-center">
                <div className="w-8 h-8 border-2 border-white border-t-transparent rounded-full animate-spin" />
              </div>
            )}
            {camActive && (
              <button onClick={flip} className="absolute top-2 right-2 w-9 h-9 rounded-full bg-black/40 hover:bg-black/60 flex items-center justify-center transition-colors" title="Flip camera">
                <svg viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="2" className="w-4 h-4">
                  <path d="M1 4v6h6M23 20v-6h-6" strokeLinecap="round" strokeLinejoin="round" />
                  <path d="M20.49 9A9 9 0 005.64 5.64L1 10M23 14l-4.64 4.36A9 9 0 013.51 15" strokeLinecap="round" strokeLinejoin="round" />
                </svg>
              </button>
            )}
            <canvas ref={canvasRef} className="hidden" />
          </div>
          <div className="flex gap-3">
            <button type="button" onClick={handleCapture} disabled={!camActive || counting}
              className="flex-1 inline-flex items-center justify-center gap-2 font-semibold text-sm px-5 py-3 rounded-pill bg-forest text-white hover:bg-forest-deep transition-colors disabled:opacity-40">
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" className="w-4 h-4">
                <path d="M23 19a2 2 0 01-2 2H3a2 2 0 01-2-2V8a2 2 0 012-2h4l2-3h6l2 3h4a2 2 0 012 2z" /><circle cx="12" cy="13" r="4" />
              </svg>
              {withCountdown && !counting ? `${label} (3s countdown)` : label}
            </button>
            <button type="button" onClick={() => { stopStream(); onCancel(); }}
              className="inline-flex items-center justify-center font-semibold text-sm px-4 py-3 rounded-pill border border-mist text-ink-soft hover:text-clay transition-colors">
              Cancel
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

// ─── DocSide capture sub-widget ───────────────────────────────────────────────
// Handles camera / upload / QR for a single side (front or back) of the ID
interface DocSideWidgetProps {
  side: "front" | "back";
  data: DocSide;
  onChange: (d: DocSide) => void;
  optional?: boolean;
}

function DocSideWidget({ side, data, onChange, optional }: DocSideWidgetProps) {
  const fileRef = useRef<HTMLInputElement>(null);
  const [mode, setMode] = useState<"choose" | "camera" | "upload-loading" | "qr">("choose");

  // Generate a QR code URL for this side — points to current page with mobile params
  const qrUrl = typeof window !== "undefined"
    ? `${window.location.origin}/kyc?mobile=id-${side}`
    : "https://villa.app/kyc?mobile=id-front";

  function handleCapture(dataUrl: string) {
    onChange({ uploaded: true, fileName: `Camera — ${side}`, dataUrl });
    setMode("choose");
  }

  function handleFile(e: React.ChangeEvent<HTMLInputElement>) {
    const file = e.target.files?.[0];
    if (!file) { setMode("choose"); return; }
    const reader = new FileReader();
    reader.onload = (ev) => onChange({ uploaded: true, fileName: file.name, dataUrl: ev.target?.result as string });
    reader.readAsDataURL(file);
    setMode("choose");
  }

  function clear() {
    onChange({ uploaded: false, fileName: "", dataUrl: "" });
    setMode("choose");
    if (fileRef.current) fileRef.current.value = "";
  }

  const sideLabel = side === "front" ? "Front of ID" : "Back of ID";

  return (
    <div className="bg-white border border-mist rounded-md overflow-hidden">
      {/* Header */}
      <div className="flex items-center justify-between px-4 py-3 border-b border-mist bg-sage/40">
        <div className="flex items-center gap-2">
          <span className={`w-6 h-6 rounded-full flex items-center justify-center text-xs font-bold ${data.uploaded ? "bg-forest text-white" : "bg-mist text-ink-soft"}`}>
            {data.uploaded ? (
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" className="w-3 h-3">
                <path d="M5 12l5 5 9-11" strokeLinecap="round" strokeLinejoin="round" />
              </svg>
            ) : side === "front" ? "F" : "B"}
          </span>
          <span className="font-semibold text-sm text-forest-deep">{sideLabel}</span>
          {optional && <span className="text-xs text-ink-soft font-mono">(optional)</span>}
        </div>
        {data.uploaded && (
          <button type="button" onClick={clear} className="text-xs text-ink-soft hover:text-clay transition-colors">Retake / replace</button>
        )}
      </div>

      <div className="p-4">
        {data.uploaded && data.dataUrl ? (
          // Preview
          // eslint-disable-next-line @next/next/no-img-element
          <img src={data.dataUrl} alt={sideLabel} className="w-full object-contain rounded-sm" style={{ maxHeight: 200, background: "#F4F6F0" }} />
        ) : mode === "choose" ? (
          // Option grid
          <div className="grid grid-cols-3 gap-2">
            {[
              { id: "camera", icon: (
                <svg viewBox="0 0 24 24" fill="none" stroke="#1E4A3D" strokeWidth="1.8" className="w-6 h-6">
                  <path d="M23 19a2 2 0 01-2 2H3a2 2 0 01-2-2V8a2 2 0 012-2h4l2-3h6l2 3h4a2 2 0 012 2z" /><circle cx="12" cy="13" r="4" />
                </svg>
              ), label: "Camera" },
              { id: "upload", icon: (
                <svg viewBox="0 0 24 24" fill="none" stroke="#1E4A3D" strokeWidth="1.8" className="w-6 h-6">
                  <path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M17 8l-5-5-5 5M12 3v12" strokeLinecap="round" strokeLinejoin="round" />
                </svg>
              ), label: "Upload" },
              { id: "qr", icon: (
                <svg viewBox="0 0 24 24" fill="none" stroke="#1E4A3D" strokeWidth="1.8" className="w-6 h-6">
                  <rect x="3" y="3" width="7" height="7" rx="1" /><rect x="14" y="3" width="7" height="7" rx="1" />
                  <rect x="3" y="14" width="7" height="7" rx="1" />
                  <path d="M14 14h1v1h-1zM17 14h1v1h-1zM20 14h1v1h-1zM14 17h1v1h-1zM17 17h1v1h-1zM20 17h1v1h-1zM14 20h1v1h-1zM17 20h1v1h-1zM20 20h1v1h-1z" fill="#1E4A3D" />
                </svg>
              ), label: "Scan QR" },
            ].map(({ id, icon, label }) => (
              <button
                key={id}
                type="button"
                onClick={() => {
                  if (id === "upload") { setMode("upload-loading"); setTimeout(() => fileRef.current?.click(), 50); }
                  else setMode(id as "camera" | "qr");
                }}
                className="flex flex-col items-center gap-2 py-4 px-2 border-2 border-dashed border-mist rounded-md hover:border-forest hover:bg-sage/40 transition-colors"
              >
                <div className="w-10 h-10 rounded-full bg-sage flex items-center justify-center">{icon}</div>
                <span className="text-xs font-semibold text-forest-deep">{label}</span>
              </button>
            ))}
            <input ref={fileRef} type="file" accept="image/*,.pdf" className="hidden" onChange={handleFile} />
          </div>
        ) : mode === "camera" ? (
          <CameraWidget onCapture={handleCapture} onCancel={() => setMode("choose")} guideShape="rect" facingModeDefault="environment" label="Capture photo" />
        ) : mode === "qr" ? (
          <div>
            <p className="text-sm text-ink-soft mb-4 text-center">
              Open your phone camera app and point it at this code. It will open like a link — tap it, then use your phone to capture the {side === "front" ? "front" : "back"} of your ID.
            </p>
            <div className="flex justify-center mb-3">
              <div className="border-4 border-forest rounded-xl p-4 bg-white shadow-card inline-block">
                <RealQRCode url={qrUrl} size={240} />
              </div>
            </div>
            <div className="bg-[#E8F2EC] border border-forest rounded-sm px-4 py-3 text-xs text-center mb-3">
              <span className="text-forest font-semibold">How to scan:</span>{" "}
              <span className="text-ink-soft">Open your phone&apos;s camera (no app needed) → point at the code → tap the link that appears.</span>
            </div>
            <p className="text-xs text-ink-soft text-center mb-4">
              Or open this link directly on your phone:{" "}
              <a href={qrUrl} target="_blank" rel="noopener noreferrer" className="text-forest font-semibold underline break-all">{qrUrl}</a>
            </p>
            <button type="button" onClick={() => setMode("choose")} className="text-sm text-ink-soft hover:text-clay underline block mx-auto">← Go back</button>
          </div>
        ) : (
          // upload loading spinner
          <div className="flex flex-col items-center justify-center gap-3 py-8">
            <div className="w-8 h-8 border-2 border-forest border-t-transparent rounded-full animate-spin" />
            <span className="text-sm text-ink-soft">Opening file picker…</span>
            <button type="button" onClick={() => setMode("choose")} className="text-xs text-ink-soft hover:text-clay underline">Cancel</button>
            <input ref={fileRef} type="file" accept="image/*,.pdf" className="hidden" onChange={handleFile} />
          </div>
        )}
      </div>
    </div>
  );
}

// ─── Step 1: Personal details ────────────────────────────────────────────────
function PersonalStep({ data, onChange, onNext }: {
  data: PersonalInfo; onChange: (d: PersonalInfo) => void; onNext: () => void;
}) {
  function set(k: keyof PersonalInfo, v: string) { onChange({ ...data, [k]: v }); }
  const valid = data.fullName && data.phone && data.dob && data.address && data.town && data.region;

  return (
    <div>
      <h2 className="font-display font-semibold text-2xl text-forest-deep mb-1">Personal details</h2>
      <p className="text-sm text-ink-soft mb-6">This information is used to verify your identity and will not be shared publicly.</p>

      <div className="grid grid-cols-1 sm:grid-cols-2 gap-5">
        <div className="sm:col-span-2">
          <FieldLabel>I am a</FieldLabel>
          <div className="grid grid-cols-2 gap-3">
            {(["landlord", "agent"] as const).map((r) => (
              <button key={r} type="button" onClick={() => set("role", r)}
                className={`text-left border rounded-md p-3 transition-colors text-sm ${data.role === r ? "border-forest bg-[#E8F2EC]" : "border-mist bg-white hover:border-forest"}`}>
                <div className="font-semibold text-forest-deep capitalize">{r}</div>
                <div className="text-xs text-ink-soft mt-0.5">{r === "landlord" ? "I own the property" : "I represent the property owner"}</div>
              </button>
            ))}
          </div>
        </div>
        <div className="sm:col-span-2">
          <FieldLabel>Full legal name</FieldLabel>
          <Input value={data.fullName} onChange={(e) => set("fullName", e.target.value)} placeholder="As it appears on your ID" />
        </div>
        <div>
          <FieldLabel>Phone number</FieldLabel>
          <Input type="tel" value={data.phone} onChange={(e) => set("phone", e.target.value)} placeholder="024 000 0000" />
        </div>
        <div>
          <FieldLabel>Date of birth</FieldLabel>
          <Input type="date" value={data.dob} onChange={(e) => set("dob", e.target.value)} />
        </div>
        <div className="sm:col-span-2">
          <FieldLabel>Residential address</FieldLabel>
          <Input value={data.address} onChange={(e) => set("address", e.target.value)} placeholder="Street or area" />
        </div>
        <div>
          <FieldLabel>Town / city</FieldLabel>
          <Input value={data.town} onChange={(e) => set("town", e.target.value)} placeholder="e.g. Akim Oda" />
        </div>
        <div>
          <FieldLabel>Region</FieldLabel>
          <Select value={data.region} onChange={(e) => set("region", e.target.value)}>
            <option value="">Select region</option>
            {REGIONS.map((r) => <option key={r}>{r}</option>)}
          </Select>
        </div>
      </div>
      <div className="mt-8 flex justify-end">
        <Btn onClick={onNext} disabled={!valid}>Continue to identity →</Btn>
      </div>
    </div>
  );
}

// ─── Step 2: Identity document ───────────────────────────────────────────────
function IdentityStep({ data, onChange, onNext, onBack }: {
  data: IdentityDoc; onChange: (d: IdentityDoc) => void; onNext: () => void; onBack: () => void;
}) {
  const needsBack = data.docType !== "Passport"; // Passport is single-sided
  const valid = data.docType && data.docNumber && data.front.uploaded && (!needsBack || data.back.uploaded);

  return (
    <div>
      <h2 className="font-display font-semibold text-2xl text-forest-deep mb-1">Identity document</h2>
      <p className="text-sm text-ink-soft mb-6">
        Provide clear photos of both sides of your ID. You can use your camera, upload a photo, or scan a QR code to capture on your mobile device.
      </p>

      <div className="flex flex-col gap-5">
        <div>
          <FieldLabel>Document type</FieldLabel>
          <Select value={data.docType} onChange={(e) => onChange({ ...data, docType: e.target.value })}>
            <option value="">Select document type</option>
            {DOC_TYPES.map((d) => <option key={d}>{d}</option>)}
          </Select>
        </div>
        <div>
          <FieldLabel>Document number</FieldLabel>
          <Input value={data.docNumber} onChange={(e) => onChange({ ...data, docNumber: e.target.value })}
            placeholder={data.docType === "Ghana Card (National ID)" ? "GHA-000000000-0" : "Document number"} />
        </div>

        {/* Front */}
        <DocSideWidget
          side="front"
          data={data.front}
          onChange={(front) => onChange({ ...data, front })}
        />

        {/* Back */}
        {needsBack && (
          <DocSideWidget
            side="back"
            data={data.back}
            onChange={(back) => onChange({ ...data, back })}
            optional={data.docType === "SSNIT Card"}
          />
        )}

        {!data.docType && (
          <p className="text-xs text-ink-soft text-center">Select a document type above to continue.</p>
        )}

        <div className="bg-[#FBF1E1] border border-gold rounded-sm px-4 py-3 text-sm text-gold-deep">
          <strong>Important:</strong> Photos must be clear, unexpired, and show your full name, photo, and ID number on each side. Blurry or edited documents will be rejected.
        </div>
      </div>

      <div className="mt-8 flex justify-between">
        <Btn variant="ghost" onClick={onBack}>← Back</Btn>
        <Btn onClick={onNext} disabled={!valid}>Continue to selfie →</Btn>
      </div>
    </div>
  );
}

// ─── Step 3: Selfie ──────────────────────────────────────────────────────────
function SelfieStep({ data, onChange, onNext, onBack }: {
  data: SelfieData; onChange: (d: SelfieData) => void; onNext: () => void; onBack: () => void;
}) {
  const [mode, setMode] = useState<"choose" | "camera" | "qr-show">("choose");
  const [preview, setPreview] = useState<string | null>(data.dataUrl || null);

  const qrUrl = typeof window !== "undefined"
    ? `${window.location.origin}/kyc?mobile=selfie`
    : "https://villa.app/kyc?mobile=selfie";

  function handleCapture(dataUrl: string) {
    setPreview(dataUrl);
    onChange({ captured: true, dataUrl });
    setMode("choose");
  }

  function retake() {
    setPreview(null);
    onChange({ captured: false, dataUrl: "" });
    setMode("choose");
  }

  return (
    <div>
      <h2 className="font-display font-semibold text-2xl text-forest-deep mb-1">Selfie verification</h2>
      <p className="text-sm text-ink-soft mb-5">
        Take a live photo of yourself holding your ID next to your face. This confirms you are the person named on the document.
      </p>

      {/* Tips */}
      <div className="grid grid-cols-2 sm:grid-cols-4 gap-2 mb-5">
        {[
          { label: "Face clearly visible", icon: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" className="w-6 h-6 text-forest"><circle cx="12" cy="8" r="4"/><path d="M4 20c0-4 3.6-7 8-7s8 3 8 7" strokeLinecap="round"/></svg> },
          { label: "ID held next to face",  icon: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" className="w-6 h-6 text-forest"><rect x="2" y="5" width="20" height="14" rx="2"/><circle cx="8" cy="12" r="2"/><path d="M14 9h4M14 12h4" strokeLinecap="round"/></svg> },
          { label: "Good lighting",         icon: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" className="w-6 h-6 text-forest"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M2 12h2M20 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42" strokeLinecap="round"/></svg> },
          { label: "ID text readable",      icon: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" className="w-6 h-6 text-forest"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.35-4.35" strokeLinecap="round"/></svg> },
        ].map(({ icon, label }) => (
          <div key={label} className="flex flex-col items-center text-center gap-1.5 bg-white border border-mist rounded-sm p-3">
            <span>{icon}</span>
            <span className="text-xs text-ink-soft">{label}</span>
          </div>
        ))}
      </div>

      {/* Captured preview */}
      {data.captured && preview ? (
        <div className="bg-ink rounded-xl overflow-hidden mb-4 relative">
          {/* eslint-disable-next-line @next/next/no-img-element */}
          <img src={preview} alt="Your selfie" className="w-full object-cover" style={{ maxHeight: 380 }} />
          <div className="absolute top-3 left-3 flex items-center gap-2 bg-forest/90 text-white text-xs font-mono uppercase tracking-wider px-3 py-1.5 rounded-pill">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" className="w-3.5 h-3.5">
              <path d="M5 12l5 5 9-11" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
            Selfie captured
          </div>
        </div>
      ) : mode === "choose" ? (
        /* Choice screen */
        <div className="grid grid-cols-1 sm:grid-cols-3 gap-3 mb-5">
          {[
            { id: "camera", icon: (
              <svg viewBox="0 0 24 24" fill="none" stroke="#1E4A3D" strokeWidth="1.8" className="w-7 h-7">
                <path d="M23 19a2 2 0 01-2 2H3a2 2 0 01-2-2V8a2 2 0 012-2h4l2-3h6l2 3h4a2 2 0 012 2z" /><circle cx="12" cy="13" r="4" />
              </svg>
            ), label: "Use this device", sub: "Webcam or laptop camera" },
            { id: "qr-show", icon: (
              <svg viewBox="0 0 24 24" fill="none" stroke="#1E4A3D" strokeWidth="1.8" className="w-7 h-7">
                <rect x="3" y="3" width="7" height="7" rx="1" /><rect x="14" y="3" width="7" height="7" rx="1" />
                <rect x="3" y="14" width="7" height="7" rx="1" />
                <path d="M14 14h1v1h-1zM17 14h1v1h-1zM20 14h1v1h-1zM14 17h1v1h-1zM20 20h1v1h-1z" fill="#1E4A3D" />
              </svg>
            ), label: "Use mobile phone", sub: "Scan QR to open on phone" },

          ].map(({ id, icon, label, sub }) => (
            <button key={id} type="button" onClick={() => setMode(id as typeof mode)}
              className="flex flex-col items-center gap-3 p-5 border-2 border-dashed border-mist rounded-md hover:border-forest hover:bg-sage/40 transition-colors">
              <div className="w-14 h-14 rounded-full bg-sage flex items-center justify-center">{icon}</div>
              <div className="text-center">
                <div className="font-semibold text-sm text-forest-deep">{label}</div>
                <div className="text-xs text-ink-soft mt-0.5">{sub}</div>
              </div>
            </button>
          ))}
        </div>
      ) : mode === "camera" ? (
        <div className="mb-5">
          <CameraWidget
            onCapture={handleCapture}
            onCancel={() => setMode("choose")}
            guideShape="oval"
            facingModeDefault="user"
            countdown
            label="Take selfie"
          />
        </div>
      ) : mode === "qr-show" ? (
        <div className="mb-5">
          <p className="text-sm text-ink-soft mb-4 text-center">
            Open your phone camera app and point it at this code. It will open this selfie step on your phone so you can take the photo with your phone&apos;s front camera.
          </p>
          <div className="flex justify-center mb-3">
            <div className="border-4 border-forest rounded-xl p-4 bg-white shadow-card inline-block">
              <RealQRCode url={qrUrl} size={260} />
            </div>
          </div>
          <div className="bg-[#E8F2EC] border border-forest rounded-sm px-4 py-3 text-xs text-center mb-3">
            <span className="text-forest font-semibold">How to scan:</span>{" "}
            <span className="text-ink-soft">Open your phone camera (no app needed) → point at the code → tap the link that appears.</span>
          </div>
          <p className="text-xs text-ink-soft text-center mb-2">
            Or open this link directly on your phone:{" "}
            <a href={qrUrl} target="_blank" rel="noopener noreferrer" className="text-forest font-semibold underline break-all">{qrUrl}</a>
          </p>
          <button type="button" onClick={() => setMode("choose")} className="mt-4 text-sm text-ink-soft hover:text-clay underline block mx-auto">← Go back</button>
        </div>
      ) : null}

      {/* Retake button */}
      {data.captured && (
        <div className="flex justify-center mb-5">
          <button type="button" onClick={retake}
            className="inline-flex items-center justify-center gap-2 font-semibold text-sm px-6 py-3 rounded-pill border border-mist text-forest hover:bg-forest hover:border-forest hover:text-white transition-colors">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" className="w-4 h-4">
              <path d="M1 4v6h6M23 20v-6h-6" strokeLinecap="round" strokeLinejoin="round" />
              <path d="M20.49 9A9 9 0 005.64 5.64L1 10M23 14l-4.64 4.36A9 9 0 013.51 15" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
            Retake selfie
          </button>
        </div>
      )}

      <div className="bg-sage border border-mist rounded-sm px-4 py-3 text-xs text-ink-soft">
        Your camera feed is processed entirely on your device — nothing is streamed or saved until you click &quot;Review &amp; submit&quot;.
      </div>

      <div className="mt-8 flex justify-between">
        <Btn variant="ghost" onClick={onBack}>← Back</Btn>
        <Btn onClick={onNext} disabled={!data.captured}>Review &amp; submit →</Btn>
      </div>
    </div>
  );
}

// ─── Step 4: Property document (landlords only) ───────────────────────────────
function PropertyDocStep({ data, onChange, onNext, onBack }: {
  data: PropertyDoc; onChange: (d: PropertyDoc) => void; onNext: () => void; onBack: () => void;
}) {
  const fileRef = useRef<HTMLInputElement>(null);

  function handleFile(e: React.ChangeEvent<HTMLInputElement>) {
    const file = e.target.files?.[0]; if (!file) return;
    const reader = new FileReader();
    reader.onload = (ev) => onChange({ ...data, uploaded: true, fileName: file.name, dataUrl: ev.target?.result as string });
    reader.readAsDataURL(file);
  }

  const valid = data.uploaded && data.docType;

  return (
    <div>
      <h2 className="font-display font-semibold text-2xl text-forest-deep mb-1">Property document</h2>
      <p className="text-sm text-ink-soft mb-6">
        As a landlord, you must provide proof that you own or have authority over the property you intend to list on Villa. This document is reviewed by the Villa team and is not shown publicly.
      </p>

      <div className="flex flex-col gap-5">
        <div>
          <label className="block font-mono text-xs uppercase tracking-widest text-ink-soft mb-2">Document type</label>
          <select value={data.docType} onChange={(e) => onChange({ ...data, docType: e.target.value })}
            className="w-full border border-mist rounded-sm px-4 py-3 text-sm bg-white text-ink focus:outline-2 focus:outline-gold focus:border-forest">
            <option value="">Select document type</option>
            {LANDLORD_PROPERTY_DOCS.map((d) => <option key={d}>{d}</option>)}
          </select>
        </div>

        <div>
          <label className="block font-mono text-xs uppercase tracking-widest text-ink-soft mb-2">Upload document</label>
          <input ref={fileRef} type="file" accept="image/*,.pdf" className="hidden" onChange={handleFile} />
          {data.uploaded ? (
            <div className="border border-forest rounded-md overflow-hidden">
              {data.dataUrl && data.dataUrl.startsWith("data:image") ? (
                // eslint-disable-next-line @next/next/no-img-element
                <img src={data.dataUrl} alt="Property document"
                  className="w-full object-contain border-b border-mist"
                  style={{ maxHeight: 220, background: "#F4F6F0" }} />
              ) : (
                <div className="h-32 bg-sage flex flex-col items-center justify-center gap-2">
                  <svg viewBox="0 0 24 24" fill="none" stroke="#1E4A3D" strokeWidth="1.6" className="w-8 h-8">
                    <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/>
                    <polyline points="14 2 14 8 20 8"/>
                    <line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/>
                  </svg>
                  <span className="text-sm font-semibold text-forest-deep">{data.fileName}</span>
                </div>
              )}
              <div className="flex items-center justify-between px-4 py-3 bg-[#E8F2EC]">
                <div className="flex items-center gap-2">
                  <svg viewBox="0 0 24 24" fill="none" stroke="#1E4A3D" strokeWidth="2" className="w-4 h-4 shrink-0">
                    <path d="M5 12l5 5 9-11" strokeLinecap="round" strokeLinejoin="round"/>
                  </svg>
                  <span className="text-sm font-semibold text-forest-deep truncate max-w-[260px]">{data.fileName}</span>
                </div>
                <button type="button" onClick={() => { onChange({ ...data, uploaded: false, fileName: "", dataUrl: "" }); if (fileRef.current) fileRef.current.value = ""; }}
                  className="text-xs text-ink-soft hover:text-clay transition-colors ml-3 shrink-0">Replace</button>
              </div>
            </div>
          ) : (
            <button type="button" onClick={() => fileRef.current?.click()}
              className="w-full border-2 border-dashed border-mist rounded-md p-10 text-center hover:border-forest transition-colors group">
              <svg viewBox="0 0 24 24" fill="none" stroke="#5B6B63" strokeWidth="1.6" className="w-10 h-10 mx-auto mb-3 group-hover:stroke-forest transition-colors">
                <path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M17 8l-5-5-5 5M12 3v12" strokeLinecap="round" strokeLinejoin="round"/>
              </svg>
              <p className="text-sm text-ink-soft"><strong className="text-forest">Click to upload</strong> your property document</p>
              <p className="text-xs text-ink-soft mt-1">JPG, PNG, or PDF — max 10MB</p>
            </button>
          )}
        </div>

        <div className="bg-[#FBF1E1] border border-gold rounded-sm px-4 py-3 text-xs text-gold-deep">
          Accepted documents include: property title deed, land certificate, tenancy agreement, purchase receipt, or a utility bill in the property owner&apos;s name. The document must clearly show the property address.
        </div>
      </div>

      <div className="mt-8 flex justify-between">
        <Btn variant="ghost" onClick={onBack}>← Back</Btn>
        <Btn onClick={onNext} disabled={!valid}>Review & submit →</Btn>
      </div>
    </div>
  );
}

// ─── Step 5: Review & submit ─────────────────────────────────────────────────
function ReviewStep({ personal, identity, selfieDataUrl, propertyDoc, onSubmit, onBack }: {
  personal: PersonalInfo; identity: IdentityDoc; selfieDataUrl: string;
  propertyDoc: PropertyDoc | null;
  onSubmit: () => Promise<void>; onBack: () => void;
}) {
  const [agreed, setAgreed] = useState(false);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);

  async function submit() {
    setBusy(true);
    setError(null);
    try {
      await onSubmit();
    } catch (e) {
      setError(e instanceof ApiError ? e.message : "Submission failed. Please try again.");
      setBusy(false);
    }
  }

  function Row({ label, value }: { label: string; value: string }) {
    return (
      <div className="flex justify-between py-3 border-b border-mist last:border-b-0 text-sm">
        <span className="text-ink-soft">{label}</span>
        <span className="font-medium text-ink text-right max-w-[60%]">{value}</span>
      </div>
    );
  }

  function ImgPreview({ src, label }: { src: string; label: string }) {
    return (
      <div className="flex-1 min-w-0">
        <div className="font-mono text-[10px] uppercase tracking-wider text-ink-soft mb-1">{label}</div>
        {src ? (
          // eslint-disable-next-line @next/next/no-img-element
          <img src={src} alt={label} className="w-full rounded-sm object-contain border border-mist" style={{ maxHeight: 180, background: "#F4F6F0" }} />
        ) : (
          <div className="h-28 bg-sage border border-mist rounded-sm flex items-center justify-center text-xs text-ink-soft font-mono uppercase tracking-wider">
            Not provided
          </div>
        )}
      </div>
    );
  }

  const needsBack = identity.docType !== "Passport";

  return (
    <div>
      <h2 className="font-display font-semibold text-2xl text-forest-deep mb-1">Review your details</h2>
      <p className="text-sm text-ink-soft mb-6">Check everything carefully before submitting. Your application will be reviewed by the Villa team.</p>

      <div className="flex flex-col gap-5 mb-6">
        {/* Personal */}
        <div className="bg-white border border-mist rounded-md p-5">
          <div className="font-mono text-xs uppercase tracking-widest text-gold-deep mb-3">Personal details</div>
          <Row label="Role"          value={personal.role === "landlord" ? "Landlord" : "Agent"} />
          <Row label="Full name"     value={personal.fullName} />
          <Row label="Phone"         value={personal.phone} />
          <Row label="Date of birth" value={personal.dob} />
          <Row label="Address"       value={personal.address} />
          <Row label="Town"          value={personal.town} />
          <Row label="Region"        value={personal.region} />
        </div>

        {/* ID document details */}
        <div className="bg-white border border-mist rounded-md p-5">
          <div className="font-mono text-xs uppercase tracking-widest text-gold-deep mb-3">Identity document</div>
          <Row label="Document type"   value={identity.docType} />
          <Row label="Document number" value={identity.docNumber} />
        </div>

        {/* ID photos side by side */}
        <div className="bg-white border border-mist rounded-md p-5">
          <div className="font-mono text-xs uppercase tracking-widest text-gold-deep mb-4">Document photos</div>
          <div className="flex gap-3 flex-wrap sm:flex-nowrap">
            <ImgPreview src={identity.front.dataUrl} label="Front" />
            {needsBack && <ImgPreview src={identity.back.dataUrl} label="Back" />}
          </div>
          {/* Filenames */}
          <div className="flex gap-3 mt-2 flex-wrap sm:flex-nowrap">
            <p className="flex-1 text-xs text-ink-soft truncate">
              <span className="font-medium">Front:</span> {identity.front.fileName || "—"}
            </p>
            {needsBack && (
              <p className="flex-1 text-xs text-ink-soft truncate">
                <span className="font-medium">Back:</span> {identity.back.fileName || "—"}
              </p>
            )}
          </div>
        </div>

        {/* Selfie */}
        <div className="bg-white border border-mist rounded-md overflow-hidden">
          <div className="px-5 pt-5 pb-2">
            <div className="font-mono text-xs uppercase tracking-widest text-gold-deep mb-1">Selfie with ID</div>
            <p className="text-xs text-ink-soft">Photo of you holding your identity document</p>
          </div>
          {selfieDataUrl ? (
            <div>
              {/* eslint-disable-next-line @next/next/no-img-element */}
              <img src={selfieDataUrl} alt="Your selfie holding ID" className="w-full object-cover border-t border-mist" style={{ maxHeight: 320, background: "#1A2420" }} />
              <div className="px-5 py-3 border-t border-mist flex items-center gap-2">
                <svg viewBox="0 0 24 24" fill="none" stroke="#1E4A3D" strokeWidth="2" className="w-4 h-4 shrink-0">
                  <path d="M5 12l5 5 9-11" strokeLinecap="round" strokeLinejoin="round" />
                </svg>
                <span className="text-xs text-forest font-medium">Selfie captured</span>
              </div>
            </div>
          ) : (
            <div className="px-5 pb-5">
              <div className="h-24 bg-sage border border-mist rounded-sm flex items-center justify-center text-xs text-ink-soft font-mono uppercase tracking-wider">
                No selfie provided
              </div>
            </div>
          )}
        </div>
      </div>

      {/* Property document (landlords only) */}
      {propertyDoc && (
        <div className="bg-white border border-mist rounded-md overflow-hidden mb-5">
          <div className="px-5 py-4 border-b border-mist">
            <div className="font-mono text-xs uppercase tracking-widest text-gold-deep">Property document</div>
          </div>
          <div className="p-5 flex flex-col gap-3">
            <div className="flex justify-between text-sm py-2 border-b border-mist">
              <span className="text-ink-soft">Document type</span>
              <span className="font-medium text-ink">{propertyDoc.docType}</span>
            </div>
            <div className="flex justify-between text-sm py-2 border-b border-mist">
              <span className="text-ink-soft">File</span>
              <span className="font-medium text-ink truncate max-w-[55%]">{propertyDoc.fileName}</span>
            </div>
            {propertyDoc.dataUrl && propertyDoc.dataUrl.startsWith("data:image") ? (
              // eslint-disable-next-line @next/next/no-img-element
              <img src={propertyDoc.dataUrl} alt="Property document"
                className="w-full rounded-sm object-contain border border-mist mt-2"
                style={{ maxHeight: 200, background: "#F4F6F0" }} />
            ) : propertyDoc.uploaded ? (
              <div className="h-24 bg-sage border border-mist rounded-sm flex flex-col items-center justify-center gap-1.5 mt-2">
                <svg viewBox="0 0 24 24" fill="none" stroke="#1E4A3D" strokeWidth="1.6" className="w-7 h-7">
                  <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/>
                  <polyline points="14 2 14 8 20 8"/>
                  <line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/>
                </svg>
                <span className="text-xs text-forest-deep font-semibold">{propertyDoc.fileName}</span>
              </div>
            ) : null}
          </div>
        </div>
      )}

      <label className="flex items-start gap-3 mb-6 cursor-pointer">
        <input type="checkbox" checked={agreed} onChange={(e) => setAgreed(e.target.checked)} className="w-4 h-4 mt-0.5 accent-forest shrink-0" />
        <span className="text-sm text-ink-soft">
          I confirm that all information provided is accurate and belongs to me. I understand that providing false information may result in permanent account suspension.
        </span>
      </label>

      {error && <p className="mt-3 text-sm text-red-600">{error}</p>}
      <div className="mt-2 flex justify-between">
        <Btn variant="ghost" onClick={onBack}>← Back</Btn>
        <Btn onClick={submit} disabled={!agreed || busy}>{busy ? "Submitting…" : "Submit KYC application"}</Btn>
      </div>
    </div>
  );
}

// ─── Submitted screen ─────────────────────────────────────────────────────────
function SubmittedScreen() {
  return (
    <div className="text-center py-8">
      <VerificationStamp variant="pending" size={96} className="mx-auto mb-6" />
      <h2 className="font-display font-semibold text-2xl text-forest-deep mb-3">Application submitted</h2>
      <p className="text-ink-soft max-w-[44ch] mx-auto mb-2">
        Thanks for completing the verification process. The Villa team will review your application within <strong>1–2 business days</strong>.
      </p>
      <p className="text-ink-soft max-w-[44ch] mx-auto mb-8">
        You&apos;ll receive an email once your account is approved. Once approved, you can add and manage property listings.
      </p>
      <div className="bg-white border border-mist rounded-md p-5 max-w-sm mx-auto mb-8 text-left">
        <div className="font-mono text-xs uppercase tracking-widest text-ink-soft mb-3">What happens next</div>
        {[
          { step: "1", label: "Review", desc: "Villa verifies your identity documents and selfie" },
          { step: "2", label: "Decision", desc: "You're notified by email — usually within 1–2 days" },
          { step: "3", label: "List properties", desc: "Once approved, add your first listing" },
        ].map(({ step, label, desc }) => (
          <div key={step} className="flex gap-3 py-3 border-b border-mist last:border-b-0">
            <div className="w-6 h-6 rounded-full bg-mist flex items-center justify-center text-xs font-bold text-forest-deep shrink-0">{step}</div>
            <div>
              <div className="text-sm font-semibold text-ink">{label}</div>
              <div className="text-xs text-ink-soft">{desc}</div>
            </div>
          </div>
        ))}
      </div>
      <div className="flex flex-col sm:flex-row gap-3 justify-center">
        <Link href="/landlord/dashboard" className="inline-flex items-center justify-center font-semibold text-sm px-6 py-3 rounded-pill bg-forest text-white hover:bg-forest-deep transition-colors">
          Go to my dashboard
        </Link>
        <Link href="/" className="inline-flex items-center justify-center font-semibold text-sm px-6 py-3 rounded-pill border border-mist text-forest hover:bg-forest hover:border-forest hover:text-white transition-colors">
          Back to home
        </Link>
      </div>
    </div>
  );
}

// ─── Main KYC page ────────────────────────────────────────────────────────────
const EMPTY_SIDE: DocSide = { uploaded: false, fileName: "", dataUrl: "" };

export default function KYCPage() {
  const [step,     setStep]     = useState<Step>("personal");
  const [personal, setPersonal] = useState<PersonalInfo>({
    fullName: "", phone: "", dob: "", address: "", town: "Akim Oda", region: "Eastern", role: "landlord",
  });
  const [identity, setIdentity] = useState<IdentityDoc>({
    docType: "", docNumber: "", front: { ...EMPTY_SIDE }, back: { ...EMPTY_SIDE },
  });
  const [selfie, setSelfie] = useState<SelfieData>({ captured: false, dataUrl: "" });
  const [propertyDoc, setPropertyDoc] = useState<PropertyDoc>({ docType: "", fileName: "", dataUrl: "", uploaded: false });

  // After selfie: landlords go to property-doc, agents go straight to review
  const afterSelfie = personal.role === "landlord" ? "property-doc" : "review";
  const beforeReview = personal.role === "landlord" ? "property-doc" : "selfie";

  // Upload captured documents, then submit the KYC application. Throws on
  // failure so ReviewStep can show the error.
  async function submitKyc() {
    const isLandlord = personal.role === "landlord";
    const needsBack = identity.docType !== "Passport";

    const front = await uploadFile(await dataUrlToFile(identity.front.dataUrl, "id-front.jpg"));
    const back = needsBack && identity.back.dataUrl
      ? await uploadFile(await dataUrlToFile(identity.back.dataUrl, "id-back.jpg"))
      : null;
    const selfieUp = await uploadFile(await dataUrlToFile(selfie.dataUrl, "selfie.jpg"));
    const propDoc = isLandlord && propertyDoc.dataUrl
      ? await uploadFile(await dataUrlToFile(propertyDoc.dataUrl, propertyDoc.fileName || "property-doc"))
      : null;

    await clientExecute("kyc.submit", {
      role: personal.role,
      fullName: personal.fullName,
      phone: personal.phone,
      dob: personal.dob,
      address: personal.address,
      town: personal.town,
      region: personal.region,
      docType: identity.docType,
      docNumber: identity.docNumber,
      frontFile: front.url,
      backFile: back?.url,
      selfieFile: selfieUp.url,
      propertyDocType: isLandlord ? propertyDoc.docType : undefined,
      propertyDocFile: isLandlord ? propDoc?.url : undefined,
      agreed: true,
    });
    setStep("submitted");
  }

  if (step === "submitted") return <div className="max-w-2xl mx-auto px-6 py-12"><SubmittedScreen /></div>;

  return (
    <div className="max-w-2xl mx-auto px-6 py-12">
      <div className="mb-8">
        <Link href="/"><VillaLogo size="sm" className="mb-6" /></Link>
        <div className="font-mono text-xs uppercase tracking-widest text-gold-deep mb-2">Identity verification</div>
        <h1 className="font-display font-semibold text-3xl text-forest-deep mb-1">Complete your KYC</h1>
        <p className="text-ink-soft text-sm">
          All landlords and agents on Villa must complete identity verification before listing properties.
          This protects tenants and keeps the platform trustworthy.
        </p>
      </div>

      <StepProgress current={step} role={personal.role} />

      <div className="bg-white border border-mist rounded-lg p-6 sm:p-8 shadow-card">
        {step === "personal" && (
          <PersonalStep data={personal} onChange={setPersonal} onNext={() => setStep("identity")} />
        )}
        {step === "identity" && (
          <IdentityStep data={identity} onChange={setIdentity}
            onNext={() => setStep("selfie")} onBack={() => setStep("personal")} />
        )}
        {step === "selfie" && (
          <SelfieStep data={selfie} onChange={setSelfie}
            onNext={() => setStep(afterSelfie)} onBack={() => setStep("identity")} />
        )}
        {step === "property-doc" && (
          <PropertyDocStep data={propertyDoc} onChange={setPropertyDoc}
            onNext={() => setStep("review")} onBack={() => setStep("selfie")} />
        )}
        {step === "review" && (
          <ReviewStep personal={personal} identity={identity} selfieDataUrl={selfie.dataUrl}
            propertyDoc={personal.role === "landlord" ? propertyDoc : null}
            onSubmit={submitKyc} onBack={() => setStep(beforeReview)} />
        )}
      </div>

      {step !== "review" && (
        <p className="text-xs text-ink-soft text-center mt-4">
          Your progress is saved automatically. You can return to this page to continue.
        </p>
      )}
    </div>
  );
}
