import React, { useState, useMemo, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { Eye, EyeOff, CheckCircle, AlertCircle, Globe } from 'lucide-react';
import { setupAPI } from '../services/api';

// ── constants ─────────────────────────────────────────────────────────────────

const TOTAL_STEPS = 4;

const CELL_NAME_RE = /^[a-z][a-z0-9-]{1,30}$/;
const DOMAIN_RE = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/i;

const DOMAIN_OPTIONS = [
  {
    value: 'pic_ngo',
    label: 'PIC.NGO subdomain',
    description: 'Free yourname.pic.ngo address — HTTPS and DDNS fully automatic.',
  },
  {
    value: 'cloudflare',
    label: 'Cloudflare DNS-01',
    description: 'Your own domain via Cloudflare API. Domain must use Cloudflare nameservers.',
  },
  {
    value: 'duckdns',
    label: 'DuckDNS',
    description: 'Free *.duckdns.org subdomain with automatic DNS-01 challenge.',
  },
  {
    value: 'http01',
    label: 'Any domain (HTTP-01)',
    description: 'Any domain via standard ACME. Port 80 must be publicly reachable.',
  },
  {
    value: 'lan',
    label: 'Local only',
    description: 'No public domain. Accessible only on your local network and via VPN.',
  },
];

// ── helpers ───────────────────────────────────────────────────────────────────

function getAllTimezones() {
  try { return Intl.supportedValuesOf('timeZone'); }
  catch {
    return [
      'UTC', 'America/New_York', 'America/Chicago', 'America/Denver',
      'America/Los_Angeles', 'Europe/London', 'Europe/Paris', 'Europe/Berlin',
      'Asia/Tokyo', 'Asia/Shanghai', 'Australia/Sydney',
    ];
  }
}

function passwordStrength(pw) {
  if (!pw) return { label: '', color: '', width: '0%', score: 0 };
  let score = 0;
  if (pw.length >= 12) score++;
  if (pw.length >= 16) score++;
  if (/[A-Z]/.test(pw)) score++;
  if (/[a-z]/.test(pw)) score++;
  if (/[0-9]/.test(pw)) score++;
  if (/[^A-Za-z0-9]/.test(pw)) score++;
  if (score <= 2) return { label: 'Weak',   color: 'bg-red-500',    width: '20%', score };
  if (score === 3) return { label: 'Fair',   color: 'bg-yellow-500', width: '45%', score };
  if (score === 4) return { label: 'Good',   color: 'bg-blue-500',   width: '70%', score };
  return               { label: 'Strong', color: 'bg-green-500',  width: '100%', score };
}

function meetsApiRequirements(pw) {
  return pw.length >= 12 && /[A-Z]/.test(pw) && /[a-z]/.test(pw) && /[0-9]/.test(pw);
}

function deriveCellName(domainType, picName, duckSub, customDomain) {
  if (domainType === 'pic_ngo') return picName.toLowerCase();
  if (domainType === 'duckdns') return duckSub.toLowerCase();
  if (domainType === 'lan')     return 'cell';
  const seg = (customDomain || '').split('.')[0].toLowerCase().replace(/[^a-z0-9-]/g, '');
  return CELL_NAME_RE.test(seg) ? seg : 'cell';
}

function getDomainName(domainType, picName, duckSub, customDomain) {
  if (domainType === 'pic_ngo') return `${picName}.pic.ngo`;
  if (domainType === 'duckdns') return `${duckSub}.duckdns.org`;
  if (domainType === 'lan')     return '';
  return customDomain;
}

// ── shared UI ─────────────────────────────────────────────────────────────────

function StepHeader({ step, title, description }) {
  return (
    <div className="mb-6">
      <p className="text-xs font-medium text-blue-400 uppercase tracking-wider mb-1">
        Step {step} of {TOTAL_STEPS}
      </p>
      <h2 className="text-lg font-semibold text-white">{title}</h2>
      {description && <p className="mt-1 text-sm text-gray-400">{description}</p>}
    </div>
  );
}

function ProgressBar({ step }) {
  const pct = Math.round((step / TOTAL_STEPS) * 100);
  return (
    <div className="mb-8">
      <div className="flex justify-between text-xs text-gray-500 mb-1">
        <span>Setup progress</span><span>{pct}%</span>
      </div>
      <div className="w-full bg-gray-700 rounded-full h-1.5">
        <div
          className="bg-blue-500 h-1.5 rounded-full transition-all duration-300"
          style={{ width: `${pct}%` }}
          role="progressbar" aria-valuenow={step} aria-valuemin={1} aria-valuemax={TOTAL_STEPS}
        />
      </div>
    </div>
  );
}

function FieldError({ message }) {
  if (!message) return null;
  return (
    <p className="mt-1.5 flex items-center gap-1 text-xs text-red-400" role="alert">
      <AlertCircle className="h-3.5 w-3.5 flex-shrink-0" />{message}
    </p>
  );
}

function RadioOption({ value, selected, label, description, onChange }) {
  return (
    <label className={`flex items-start gap-3 p-3 rounded-lg border cursor-pointer transition-colors ${
      selected ? 'border-blue-500 bg-blue-950/40' : 'border-gray-700 hover:border-gray-500'
    }`}>
      <input type="radio" className="mt-0.5 accent-blue-500" value={value} checked={selected} onChange={() => onChange(value)} />
      <div>
        <div className="text-sm font-medium text-white">{label}</div>
        {description && <div className="text-xs text-gray-400 mt-0.5">{description}</div>}
      </div>
    </label>
  );
}

function NavButtons({ onBack, onNext, nextLabel = 'Next', nextDisabled = false, loading = false }) {
  return (
    <div className="flex justify-between mt-8 pt-6 border-t border-gray-700">
      {onBack ? (
        <button type="button" onClick={onBack}
          className="px-4 py-2 text-sm font-medium text-gray-300 bg-gray-800 hover:bg-gray-700 border border-gray-600 rounded-md transition-colors">
          Back
        </button>
      ) : <div />}
      <button type="button" onClick={onNext} disabled={nextDisabled || loading}
        className="px-5 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-500 disabled:opacity-50 disabled:cursor-not-allowed rounded-md transition-colors flex items-center gap-2">
        {loading && <span className="animate-spin rounded-full h-3.5 w-3.5 border-b-2 border-white" />}
        {nextLabel}
      </button>
    </div>
  );
}

function TokenVerifyButton({ onVerify, status }) {
  const label = status === 'checking' ? 'Verifying…'
    : status === 'valid'   ? '✓ Valid'
    : status === 'invalid' ? 'Invalid — retry'
    : 'Verify token';
  const cls = status === 'valid'   ? 'text-green-400 border-green-600'
    : status === 'invalid' ? 'text-red-400 border-red-600'
    : 'text-blue-400 border-blue-600 hover:bg-blue-900/20';
  return (
    <button type="button" onClick={onVerify} disabled={status === 'checking'}
      className={`mt-2 px-3 py-1 text-xs border rounded transition-colors ${cls}`}>
      {label}
    </button>
  );
}

// ── step 1: password ──────────────────────────────────────────────────────────

function Step1Password({ password, confirm, onChangePassword, onChangeConfirm, onNext }) {
  const [showPw, setShowPw] = useState(false);
  const [showCf, setShowCf] = useState(false);
  const [errors, setErrors] = useState({});
  const strength = passwordStrength(password);
  const ready = meetsApiRequirements(password) && password === confirm;

  const handleNext = async () => {
    const e = {};
    if (!meetsApiRequirements(password))
      e.password = 'Minimum 12 characters with uppercase, lowercase, and a digit.';
    if (password !== confirm)
      e.confirm = 'Passwords do not match.';
    setErrors(e);
    if (Object.keys(e).length > 0) return;
    try {
      await setupAPI.validate('password', { password });
      onNext();
    } catch (ex) {
      setErrors({ password: ex?.response?.data?.errors?.[0] || 'Password validation failed.' });
    }
  };

  return (
    <div>
      <StepHeader step={1} title="Set admin password"
        description="This is the password for the admin account. Store it securely." />
      <div className="space-y-4">
        <div>
          <label className="block text-sm text-gray-400 mb-1.5" htmlFor="pw">
            Password <span className="text-red-400">*</span>
          </label>
          <div className="relative">
            <input id="pw" type={showPw ? 'text' : 'password'} autoComplete="new-password"
              value={password} onChange={e => { onChangePassword(e.target.value); setErrors(p => ({...p, password: ''})); }}
              onKeyDown={e => e.key === 'Enter' && handleNext()}
              className="w-full bg-gray-800 border border-gray-600 rounded px-3 py-2 pr-10 text-white text-sm focus:outline-none focus:border-blue-500" />
            <button type="button" onClick={() => setShowPw(v => !v)}
              className="absolute right-2.5 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-200">
              {showPw ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
            </button>
          </div>
          {password && (
            <div className="mt-2">
              <div className="w-full bg-gray-700 rounded-full h-1">
                <div className={`h-1 rounded-full transition-all ${strength.color}`} style={{ width: strength.width }} />
              </div>
              <p className="text-xs text-gray-400 mt-1">{strength.label}</p>
            </div>
          )}
          <FieldError message={errors.password} />
        </div>
        <div>
          <label className="block text-sm text-gray-400 mb-1.5" htmlFor="pw-confirm">
            Confirm password <span className="text-red-400">*</span>
          </label>
          <div className="relative">
            <input id="pw-confirm" type={showCf ? 'text' : 'password'} autoComplete="new-password"
              value={confirm} onChange={e => { onChangeConfirm(e.target.value); setErrors(p => ({...p, confirm: ''})); }}
              onKeyDown={e => e.key === 'Enter' && handleNext()}
              className="w-full bg-gray-800 border border-gray-600 rounded px-3 py-2 pr-10 text-white text-sm focus:outline-none focus:border-blue-500" />
            <button type="button" onClick={() => setShowCf(v => !v)}
              className="absolute right-2.5 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-200">
              {showCf ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
            </button>
          </div>
          <FieldError message={errors.confirm} />
        </div>
        <p className="text-xs text-gray-500">
          Min 12 characters, one uppercase letter, one lowercase letter, one digit.
        </p>
      </div>
      <NavButtons onNext={handleNext} nextDisabled={!ready} />
    </div>
  );
}

// ── step 2: domain ────────────────────────────────────────────────────────────

function Step2Domain({
  domainType, onDomainType,
  picName, onPicName,
  customDomain, onCustomDomain,
  duckSub, onDuckSub,
  cloudflareToken, onCloudflareToken,
  duckdnsToken, onDuckdnsToken,
  onNext, onBack,
}) {
  const [errors, setErrors]           = useState({});
  const [picAvail, setPicAvail]       = useState(null); // null|checking|available|taken|unknown
  const [cfStatus, setCfStatus]       = useState(null);
  const [dnsStatus, setDnsStatus]     = useState(null);
  const [nextLoading, setNextLoading] = useState(false);

  const checkPicAvail = async name => {
    if (!CELL_NAME_RE.test(name)) return null;
    setPicAvail('checking');
    try {
      const res = await setupAPI.validate('pic_ngo_available', { cell_name: name });
      const result = res.data?.available ? 'available' : 'taken';
      setPicAvail(result);
      return result;
    } catch {
      setPicAvail('unknown');
      return 'unknown';
    }
  };

  const verifyCf = async () => {
    setCfStatus('checking');
    try {
      const res = await setupAPI.validate('cloudflare_token', { token: cloudflareToken });
      const result = res.data?.valid ? 'valid' : 'invalid';
      setCfStatus(result);
      return result;
    } catch { setCfStatus('invalid'); return 'invalid'; }
  };

  const verifyDns = async () => {
    setDnsStatus('checking');
    try {
      const res = await setupAPI.validate('duckdns_token', { subdomain: duckSub, token: duckdnsToken });
      const result = res.data?.valid ? 'valid' : 'invalid';
      setDnsStatus(result);
      return result;
    } catch { setDnsStatus('invalid'); return 'invalid'; }
  };

  const handleNext = async () => {
    const e = {};
    if (domainType === 'pic_ngo') {
      if (!picName) {
        e.name = 'Subdomain is required.';
      } else if (!CELL_NAME_RE.test(picName)) {
        e.name = 'Lowercase letters, digits, hyphens. 2–31 chars, must start with a letter.';
      } else if (picAvail !== 'available') {
        setNextLoading(true);
        const result = await checkPicAvail(picName);
        setNextLoading(false);
        if (result === 'taken')
          e.name = 'This subdomain is already taken. Choose another.';
        else if (result !== 'available')
          e.name = 'Could not reach the DDNS service. Check your connection or choose a different domain option.';
      }
    } else if (domainType === 'cloudflare') {
      if (!customDomain || !DOMAIN_RE.test(customDomain)) e.domain = 'Enter a valid domain (e.g. home.example.com).';
      if (!cloudflareToken.trim()) {
        e.token = 'Cloudflare API token is required.';
      } else if (cfStatus !== 'valid') {
        setNextLoading(true);
        const result = await verifyCf();
        setNextLoading(false);
        if (result !== 'valid') e.token = 'Cloudflare token is invalid or could not be verified.';
      }
    } else if (domainType === 'duckdns') {
      if (!duckSub) e.name = 'DuckDNS subdomain is required.';
      if (!duckdnsToken.trim()) {
        e.token = 'DuckDNS token is required.';
      } else if (dnsStatus !== 'valid') {
        setNextLoading(true);
        const result = await verifyDns();
        setNextLoading(false);
        if (result !== 'valid') e.token = 'DuckDNS token is invalid or could not be verified.';
      }
    } else if (domainType === 'http01') {
      if (!customDomain || !DOMAIN_RE.test(customDomain)) e.domain = 'Enter a valid domain (e.g. home.example.com).';
    }
    setErrors(e);
    if (Object.keys(e).length === 0) onNext();
  };

  return (
    <div>
      <StepHeader step={2} title="How will your cell be reached?"
        description="Choose how your cell will be accessible from the internet." />

      <div className="space-y-2 mb-5">
        {DOMAIN_OPTIONS.map(opt => (
          <RadioOption key={opt.value} value={opt.value} label={opt.label} description={opt.description}
            selected={domainType === opt.value}
            onChange={v => { onDomainType(v); setErrors({}); setPicAvail(null); setCfStatus(null); setDnsStatus(null); }} />
        ))}
      </div>

      {/* pic.ngo subdomain name */}
      {domainType === 'pic_ngo' && (
        <div className="mt-4 space-y-3">
          <div>
            <label className="block text-sm text-gray-400 mb-1.5">
              Subdomain <span className="text-red-400">*</span>
            </label>
            <input type="text" autoComplete="off" spellCheck={false}
              value={picName}
              onChange={e => { onPicName(e.target.value.toLowerCase()); setErrors(p => ({...p, name: ''})); setPicAvail(null); }}
              onBlur={() => picName && checkPicAvail(picName)}
              placeholder="e.g. myhome"
              className="w-full bg-gray-800 border border-gray-600 rounded px-3 py-2 text-white text-sm focus:outline-none focus:border-blue-500 placeholder-gray-600" />
            {CELL_NAME_RE.test(picName) && (
              <p className="mt-1.5 text-xs text-blue-400 flex items-center gap-1">
                <Globe className="h-3.5 w-3.5" />
                <span className="font-mono">{picName}.pic.ngo</span>
                {picAvail === 'checking'  && <span className="text-gray-400 ml-1">checking…</span>}
                {picAvail === 'available' && <span className="text-green-400 ml-1">— available</span>}
                {picAvail === 'taken'     && <span className="text-yellow-400 ml-1">— may already be taken</span>}
              </p>
            )}
            <FieldError message={errors.name} />
          </div>
        </div>
      )}

      {/* Cloudflare */}
      {domainType === 'cloudflare' && (
        <div className="mt-4 space-y-4">
          <div>
            <label className="block text-sm text-gray-400 mb-1.5">Domain <span className="text-red-400">*</span></label>
            <input type="text" autoComplete="off"
              value={customDomain}
              onChange={e => { onCustomDomain(e.target.value.toLowerCase().trim()); setErrors(p => ({...p, domain: ''})); }}
              placeholder="e.g. home.example.com"
              className="w-full bg-gray-800 border border-gray-600 rounded px-3 py-2 text-white text-sm focus:outline-none focus:border-blue-500 placeholder-gray-600" />
            <FieldError message={errors.domain} />
          </div>
          <div>
            <label className="block text-sm text-gray-400 mb-1.5">Cloudflare API token <span className="text-red-400">*</span></label>
            <input type="password" autoComplete="off"
              value={cloudflareToken}
              onChange={e => { onCloudflareToken(e.target.value); setErrors(p => ({...p, token: ''})); setCfStatus(null); }}
              placeholder="Token with Zone / DNS / Edit permission"
              className="w-full bg-gray-800 border border-gray-600 rounded px-3 py-2 text-white text-sm focus:outline-none focus:border-blue-500 placeholder-gray-600" />
            <p className="mt-1 text-xs text-gray-500">Cloudflare Dashboard → My Profile → API Tokens → Create Token</p>
            {cloudflareToken.trim() && <TokenVerifyButton onVerify={verifyCf} status={cfStatus} />}
            <FieldError message={errors.token} />
          </div>
        </div>
      )}

      {/* DuckDNS */}
      {domainType === 'duckdns' && (
        <div className="mt-4 space-y-4">
          <div>
            <label className="block text-sm text-gray-400 mb-1.5">DuckDNS subdomain <span className="text-red-400">*</span></label>
            <div className="flex items-center gap-2">
              <input type="text" autoComplete="off"
                value={duckSub}
                onChange={e => { onDuckSub(e.target.value.toLowerCase().trim()); setErrors(p => ({...p, name: ''})); setDnsStatus(null); }}
                placeholder="e.g. myhome"
                className="flex-1 bg-gray-800 border border-gray-600 rounded px-3 py-2 text-white text-sm focus:outline-none focus:border-blue-500 placeholder-gray-600" />
              <span className="text-gray-500 text-sm">.duckdns.org</span>
            </div>
            <FieldError message={errors.name} />
          </div>
          <div>
            <label className="block text-sm text-gray-400 mb-1.5">DuckDNS token <span className="text-red-400">*</span></label>
            <input type="password" autoComplete="off"
              value={duckdnsToken}
              onChange={e => { onDuckdnsToken(e.target.value); setErrors(p => ({...p, token: ''})); setDnsStatus(null); }}
              placeholder="Token from duckdns.org account page"
              className="w-full bg-gray-800 border border-gray-600 rounded px-3 py-2 text-white text-sm focus:outline-none focus:border-blue-500 placeholder-gray-600" />
            <p className="mt-1 text-xs text-gray-500">The subdomain must already exist in your DuckDNS account.</p>
            {duckdnsToken.trim() && <TokenVerifyButton onVerify={verifyDns} status={dnsStatus} />}
            <FieldError message={errors.token} />
          </div>
        </div>
      )}

      {/* HTTP-01 */}
      {domainType === 'http01' && (
        <div className="mt-4 space-y-4">
          <div>
            <label className="block text-sm text-gray-400 mb-1.5">Domain <span className="text-red-400">*</span></label>
            <input type="text" autoComplete="off"
              value={customDomain}
              onChange={e => { onCustomDomain(e.target.value.toLowerCase().trim()); setErrors(p => ({...p, domain: ''})); }}
              placeholder="e.g. home.example.com"
              className="w-full bg-gray-800 border border-gray-600 rounded px-3 py-2 text-white text-sm focus:outline-none focus:border-blue-500 placeholder-gray-600" />
            <FieldError message={errors.domain} />
          </div>
          <div className="p-3 bg-yellow-950/40 border border-yellow-700/50 rounded-lg">
            <p className="text-xs text-yellow-300">
              <span className="font-semibold">Port 80 must be publicly reachable</span> for Let's Encrypt HTTP-01.
              Ensure your router forwards port 80 to this machine before completing setup.
            </p>
          </div>
        </div>
      )}

      <NavButtons onBack={onBack} onNext={handleNext} loading={nextLoading} />
    </div>
  );
}

// ── step 3: timezone ──────────────────────────────────────────────────────────

function Step3Timezone({ value, onChange, onNext, onBack }) {
  const [query, setQuery] = useState('');
  const allZones = useMemo(() => getAllTimezones(), []);
  const filtered = useMemo(() => {
    const q = query.toLowerCase();
    return q ? allZones.filter(z => z.toLowerCase().includes(q)) : allZones;
  }, [query, allZones]);

  return (
    <div>
      <StepHeader step={3} title="Timezone" description="Used for log timestamps, cron jobs, and email headers." />
      <div>
        <label className="block text-sm text-gray-400 mb-1.5" htmlFor="tz-search">Search timezone</label>
        <input id="tz-search" type="text" value={query} onChange={e => setQuery(e.target.value)}
          placeholder="e.g. New York, Berlin, Tokyo"
          className="w-full bg-gray-800 border border-gray-600 rounded px-3 py-2 text-white text-sm focus:outline-none focus:border-blue-500 placeholder-gray-600 mb-2" />
        <label className="block text-sm text-gray-400 mb-1.5" htmlFor="tz-select">
          Select timezone <span className="text-red-400">*</span>
        </label>
        <select id="tz-select" value={value} onChange={e => onChange(e.target.value)} size={8}
          className="w-full bg-gray-800 border border-gray-600 rounded px-3 py-2 text-white text-sm focus:outline-none focus:border-blue-500">
          {filtered.map(z => <option key={z} value={z}>{z}</option>)}
        </select>
        {value && <p className="mt-2 text-xs text-gray-400">Selected: <span className="text-white">{value}</span></p>}
      </div>
      <NavButtons onBack={onBack} onNext={onNext} nextDisabled={!value} />
    </div>
  );
}

// ── step 4: review ────────────────────────────────────────────────────────────

function ReviewRow({ label, value }) {
  return (
    <div className="flex justify-between py-2.5 border-b border-gray-800 last:border-0">
      <span className="text-sm text-gray-400">{label}</span>
      <span className="text-sm text-white font-medium text-right max-w-[60%] break-words">{value}</span>
    </div>
  );
}

function Step4Review({ domainType, domainName, timezone, onBack, onSubmit, submitting, submitError }) {
  const domainDisplay = domainName || 'LAN only (no public domain)';
  const providerLabel = DOMAIN_OPTIONS.find(o => o.value === domainType)?.label || domainType;

  return (
    <div>
      <StepHeader step={4} title="Review and finish"
        description="Check your choices. You can go back to change anything." />
      <div className="bg-gray-800/50 border border-gray-700 rounded-lg px-4 py-1 mb-2">
        <ReviewRow label="Admin password" value="••••••••••••" />
        <ReviewRow label="Domain" value={domainDisplay} />
        <ReviewRow label="Provider" value={providerLabel} />
        <ReviewRow label="Timezone" value={timezone} />
      </div>
      {submitError && (
        <div className="mt-4 p-3 bg-red-950/50 border border-red-700 rounded-lg flex items-start gap-2">
          <AlertCircle className="h-4 w-4 text-red-400 flex-shrink-0 mt-0.5" />
          <p className="text-sm text-red-300">{submitError}</p>
        </div>
      )}
      <NavButtons onBack={onBack} onNext={onSubmit} nextLabel="Complete setup" loading={submitting} />
    </div>
  );
}

// ── main component ────────────────────────────────────────────────────────────

export default function Setup() {
  const navigate = useNavigate();
  const [step, setStep]           = useState(1);
  const [done, setDone]           = useState(false);
  const [setupWarnings, setSetupWarnings] = useState([]);

  const [password, setPassword]             = useState('');
  const [passwordConfirm, setPasswordConfirm] = useState('');

  const [domainType, setDomainType]         = useState('pic_ngo');
  const [picName, setPicName]               = useState('');
  const [customDomain, setCustomDomain]     = useState('');
  const [duckSub, setDuckSub]               = useState('');
  const [cloudflareToken, setCloudflareToken] = useState('');
  const [duckdnsToken, setDuckdnsToken]     = useState('');

  const [timezone, setTimezone] = useState(
    (() => { try { return Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC'; } catch { return 'UTC'; } })()
  );

  const [submitting, setSubmitting]   = useState(false);
  const [submitError, setSubmitError] = useState('');

  // Pre-fill from any previously saved config
  useEffect(() => {
    setupAPI.getStatus()
      .then(res => {
        const pre = res.data?.preconfigured;
        if (!pre) return;
        if (pre.domain_mode === 'pic_ngo' && pre.cell_name)   setPicName(pre.cell_name);
        if (pre.domain_mode === 'duckdns' && pre.cell_name)   setDuckSub(pre.cell_name);
        if (pre.domain_mode && pre.domain_mode !== 'pic_ngo' && pre.domain_mode !== 'duckdns' && pre.domain_name)
          setCustomDomain(pre.domain_name);
        if (pre.domain_mode)                                   setDomainType(pre.domain_mode);
        if (pre.cloudflare_api_token) setCloudflareToken(pre.cloudflare_api_token);
        if (pre.duckdns_token)        setDuckdnsToken(pre.duckdns_token);
      })
      .catch(() => {});
  }, []);

  const goNext = () => setStep(s => Math.min(s + 1, TOTAL_STEPS));
  const goBack = () => setStep(s => Math.max(s - 1, 1));

  const handleSubmit = async () => {
    setSubmitError('');
    setSubmitting(true);

    const cellName   = deriveCellName(domainType, picName, duckSub, customDomain);
    const domainName = getDomainName(domainType, picName, duckSub, customDomain);
    const ddnsProvider = domainType === 'lan' ? 'none' : domainType === 'http01' ? 'none' : domainType;

    const payload = {
      cell_name:     cellName,
      password,
      domain_mode:   domainType,
      domain_name:   domainName,
      timezone,
      ddns_provider: ddnsProvider,
      ...(domainType === 'cloudflare' && { cloudflare_api_token: cloudflareToken }),
      ...(domainType === 'duckdns'    && { duckdns_token: duckdnsToken }),
    };

    try {
      const res = await setupAPI.complete(payload);
      const warnings = res?.data?.warnings || [];
      setSetupWarnings(warnings);
      setDone(true);
      if (warnings.length === 0) {
        setTimeout(() => navigate('/login', { replace: true }), 2000);
      }
    } catch (e) {
      setSubmitError(
        e?.response?.data?.errors?.join(' ') ||
        e?.response?.data?.error ||
        'Setup could not be completed. Please check your entries and try again.'
      );
    } finally {
      setSubmitting(false);
    }
  };

  if (done) {
    return (
      <div className="flex items-center justify-center min-h-screen bg-gray-950">
        <div className="text-center max-w-md px-4">
          <CheckCircle className="h-12 w-12 text-green-400 mx-auto mb-4" />
          <h2 className="text-lg font-semibold text-white mb-2">Setup complete!</h2>
          {setupWarnings.length > 0 ? (
            <div className="mt-4 text-left space-y-3">
              {setupWarnings.map((w, i) => (
                <div key={i} className="flex gap-2 bg-amber-900/40 border border-amber-700 rounded-lg p-3">
                  <AlertCircle className="h-4 w-4 text-amber-400 mt-0.5 shrink-0" />
                  <p className="text-sm text-amber-200">{w}</p>
                </div>
              ))}
              <button
                onClick={() => navigate('/login', { replace: true })}
                className="mt-4 w-full py-2 px-4 bg-primary-600 hover:bg-primary-700 text-white rounded-lg text-sm font-medium"
              >
                Continue to login
              </button>
            </div>
          ) : (
            <p className="text-sm text-gray-400">Redirecting to login...</p>
          )}
        </div>
      </div>
    );
  }

  const domainName = getDomainName(domainType, picName, duckSub, customDomain);

  return (
    <div className="flex items-center justify-center min-h-screen bg-gray-950 px-4 py-10">
      <div className="w-full max-w-lg bg-gray-900 border border-gray-700 rounded-xl p-8 shadow-2xl">
        <div className="mb-6">
          <h1 className="text-xl font-bold text-white">Personal Internet Cell</h1>
          <p className="text-sm text-gray-400 mt-0.5">First-time setup</p>
        </div>

        <ProgressBar step={step} />

        {step === 1 && (
          <Step1Password
            password={password} confirm={passwordConfirm}
            onChangePassword={setPassword} onChangeConfirm={setPasswordConfirm}
            onNext={goNext}
          />
        )}
        {step === 2 && (
          <Step2Domain
            domainType={domainType} onDomainType={setDomainType}
            picName={picName} onPicName={setPicName}
            customDomain={customDomain} onCustomDomain={setCustomDomain}
            duckSub={duckSub} onDuckSub={setDuckSub}
            cloudflareToken={cloudflareToken} onCloudflareToken={setCloudflareToken}
            duckdnsToken={duckdnsToken} onDuckdnsToken={setDuckdnsToken}
            onNext={goNext} onBack={goBack}
          />
        )}
        {step === 3 && (
          <Step3Timezone value={timezone} onChange={setTimezone} onNext={goNext} onBack={goBack} />
        )}
        {step === 4 && (
          <Step4Review
            domainType={domainType} domainName={domainName}
            timezone={timezone}
            onBack={goBack} onSubmit={handleSubmit}
            submitting={submitting} submitError={submitError}
          />
        )}
      </div>
    </div>
  );
}
