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

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

const TOTAL_STEPS = 7;

const CELL_NAME_RE = /^[a-z][a-z0-9-]{1,30}$/;

const DOMAIN_OPTIONS = [
  {
    value: 'pic_ngo',
    label: 'PIC.NGO subdomain',
    description: 'Get a free yourname.pic.ngo domain — managed automatically.',
  },
  {
    value: 'custom',
    label: 'Custom domain',
    description: 'Bring your own domain. You will configure DNS records manually.',
  },
  {
    value: 'lan_only',
    label: 'LAN only',
    description: 'No public domain. Accessible only on your local network and via VPN.',
  },
];

const DDNS_OPTIONS = [
  { value: 'pic_ngo', label: 'pic.ngo (managed)', description: 'Automatic — no setup required.' },
  { value: 'cloudflare', label: 'Cloudflare', description: 'Use Cloudflare DNS with API token.' },
  { value: 'duckdns', label: 'DuckDNS', description: 'Free dynamic DNS via duckdns.org.' },
  { value: 'noip', label: 'No-IP', description: 'Free dynamic DNS via noip.com.' },
  { value: 'freedns', label: 'FreeDNS', description: 'Free DNS via freedns.afraid.org.' },
  { value: 'manual', label: 'Manual / None', description: 'You will handle DNS updates yourself.' },
];

const OPTIONAL_SERVICES = [
  { key: 'email', label: 'Email', description: 'Postfix + Dovecot IMAP/SMTP server.' },
  { key: 'calendar', label: 'Calendar & Contacts', description: 'CalDAV/CardDAV via Radicale.' },
  { key: 'files', label: 'Files (WebDAV)', description: 'WebDAV file storage accessible from any device.' },
  { key: 'webmail', label: 'Webmail UI', description: 'Browser-based email client (Roundcube).' },
];

const ALWAYS_ON_SERVICES = [
  { key: 'vpn', label: 'VPN (WireGuard)' },
  { key: 'dns', label: 'DNS (CoreDNS)' },
  { key: 'api', label: 'API (cell-api)' },
];

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

function getAllTimezones() {
  try {
    return Intl.supportedValuesOf('timeZone');
  } catch {
    // Fallback list for older browsers
    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%' };
  let score = 0;
  if (pw.length >= 12) score++;
  if (pw.length >= 16) score++;
  if (/[A-Z]/.test(pw)) score++;
  if (/[0-9]/.test(pw)) score++;
  if (/[^A-Za-z0-9]/.test(pw)) score++;
  if (score <= 1) return { label: 'Weak', color: 'bg-red-500', width: '20%' };
  if (score === 2) return { label: 'Fair', color: 'bg-yellow-500', width: '40%' };
  if (score === 3) return { label: 'Good', color: 'bg-blue-500', width: '65%' };
  return { label: 'Strong', color: 'bg-green-500', width: '100%' };
}

// ── sub-components ────────────────────────────────────────────────────────────

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>
  );
}

// ── step screens ──────────────────────────────────────────────────────────────

function Step1CellName({ value, onChange, onNext }) {
  const [error, setError] = useState('');
  const [serverError, setServerError] = useState('');
  const [loading, setLoading] = useState(false);

  const validate = () => {
    if (!value.trim()) return 'Cell name is required.';
    if (!CELL_NAME_RE.test(value))
      return 'Use lowercase letters, numbers, and hyphens only. Must start with a letter. 2–31 characters.';
    return '';
  };

  const handleNext = async () => {
    const err = validate();
    setError(err);
    setServerError('');
    if (err) return;

    setLoading(true);
    try {
      await setupAPI.validate('cell_name', { cell_name: value });
      onNext();
    } catch (e) {
      setServerError(
        e?.response?.data?.error || 'Validation failed. Please try a different name.'
      );
    } finally {
      setLoading(false);
    }
  };

  return (
    <div>
      <StepHeader
        step={1}
        title="Name your cell"
        description="This is the internal identifier for your Personal Internet Cell. It appears in hostnames and logs."
      />
      <div>
        <label className="block text-sm text-gray-400 mb-1.5" htmlFor="cell-name">
          Cell name <span className="text-red-400">*</span>
        </label>
        <input
          id="cell-name"
          type="text"
          autoComplete="off"
          spellCheck={false}
          value={value}
          onChange={e => {
            onChange(e.target.value.toLowerCase());
            setError('');
            setServerError('');
          }}
          onKeyDown={e => e.key === 'Enter' && handleNext()}
          placeholder="e.g. homelab"
          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"
          aria-describedby={error || serverError ? 'cell-name-error' : undefined}
        />
        <p className="mt-1 text-xs text-gray-500">
          Lowercase letters, numbers, hyphens. Must start with a letter. 2–31 characters.
        </p>
        <div id="cell-name-error">
          <FieldError message={error || serverError} />
        </div>
      </div>
      <NavButtons onNext={handleNext} loading={loading} nextDisabled={!value.trim()} />
    </div>
  );
}

function Step2Password({ password, confirm, onChangePassword, onChangeConfirm, onNext, onBack }) {
  const [showPw, setShowPw] = useState(false);
  const [showConfirm, setShowConfirm] = useState(false);
  const [errors, setErrors] = useState({});

  const strength = passwordStrength(password);

  const validate = () => {
    const e = {};
    if (!password) e.password = 'Password is required.';
    else if (password.length < 12) e.password = 'Password must be at least 12 characters.';
    if (!confirm) e.confirm = 'Please confirm your password.';
    else if (password !== confirm) e.confirm = 'Passwords do not match.';
    return e;
  };

  const handleNext = () => {
    const e = validate();
    setErrors(e);
    if (Object.keys(e).length === 0) onNext();
  };

  const isReady = password.length >= 12 && password === confirm;

  return (
    <div>
      <StepHeader
        step={2}
        title="Set admin password"
        description="This password protects access to your cell. Choose something strong and store it safely."
      />
      <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: '' })); }}
              className="w-full bg-gray-800 border border-gray-600 rounded px-3 py-2 pr-9 text-white text-sm focus:outline-none focus:border-blue-500"
              aria-describedby={errors.password ? 'pw-error' : undefined}
            />
            <button
              type="button"
              onClick={() => setShowPw(v => !v)}
              className="absolute inset-y-0 right-0 flex items-center px-2.5 text-gray-400 hover:text-gray-200"
              tabIndex={-1}
              aria-label={showPw ? 'Hide password' : 'Show password'}
            >
              {showPw ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
            </button>
          </div>
          {/* Strength bar */}
          {password.length > 0 && (
            <div className="mt-2">
              <div className="w-full bg-gray-700 rounded-full h-1">
                <div
                  className={`h-1 rounded-full transition-all duration-300 ${strength.color}`}
                  style={{ width: strength.width }}
                />
              </div>
              <p className="text-xs text-gray-400 mt-1">Strength: {strength.label}</p>
            </div>
          )}
          <div id="pw-error"><FieldError message={errors.password} /></div>
        </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={showConfirm ? '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-9 text-white text-sm focus:outline-none focus:border-blue-500"
              aria-describedby={errors.confirm ? 'pw-confirm-error' : undefined}
            />
            <button
              type="button"
              onClick={() => setShowConfirm(v => !v)}
              className="absolute inset-y-0 right-0 flex items-center px-2.5 text-gray-400 hover:text-gray-200"
              tabIndex={-1}
              aria-label={showConfirm ? 'Hide password' : 'Show password'}
            >
              {showConfirm ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
            </button>
          </div>
          <div id="pw-confirm-error"><FieldError message={errors.confirm} /></div>
        </div>
      </div>
      <NavButtons onBack={onBack} onNext={handleNext} nextDisabled={!isReady} />
    </div>
  );
}

function Step3Domain({ value, onChange, onNext, onBack }) {
  return (
    <div>
      <StepHeader
        step={3}
        title="Choose your domain"
        description="How will you and your peers reach this cell over the internet?"
      />
      <div className="space-y-2">
        {DOMAIN_OPTIONS.map(opt => (
          <RadioOption
            key={opt.value}
            value={opt.value}
            label={opt.label}
            description={opt.description}
            selected={value === opt.value}
            onChange={onChange}
          />
        ))}
      </div>
      <NavButtons onBack={onBack} onNext={onNext} nextDisabled={!value} />
    </div>
  );
}

function Step4DDNS({ value, onChange, onNext, onBack }) {
  return (
    <div>
      <StepHeader
        step={4}
        title="DDNS provider"
        description="Which provider will keep your dynamic IP address up to date? Credentials are configured separately after setup."
      />
      <div className="space-y-2">
        {DDNS_OPTIONS.map(opt => (
          <RadioOption
            key={opt.value}
            value={opt.value}
            label={opt.label}
            description={opt.description}
            selected={value === opt.value}
            onChange={onChange}
          />
        ))}
      </div>
      <NavButtons onBack={onBack} onNext={onNext} nextDisabled={!value} />
    </div>
  );
}

function Step5Services({ selected, onChange, onNext, onBack }) {
  const toggle = key => {
    onChange(
      selected.includes(key) ? selected.filter(k => k !== key) : [...selected, key]
    );
  };

  return (
    <div>
      <StepHeader
        step={5}
        title="Optional services"
        description="Choose which services to enable. You can change this later in Settings."
      />

      {/* Optional services */}
      <div className="space-y-2 mb-6">
        {OPTIONAL_SERVICES.map(svc => {
          const checked = selected.includes(svc.key);
          return (
            <label
              key={svc.key}
              className={`flex items-start gap-3 p-3 rounded-lg border cursor-pointer transition-colors ${
                checked ? 'border-blue-500 bg-blue-950/40' : 'border-gray-700 hover:border-gray-500'
              }`}
            >
              <input
                type="checkbox"
                className="mt-0.5 accent-blue-500"
                checked={checked}
                onChange={() => toggle(svc.key)}
              />
              <div>
                <div className="text-sm font-medium text-white">{svc.label}</div>
                <div className="text-xs text-gray-400 mt-0.5">{svc.description}</div>
              </div>
            </label>
          );
        })}
      </div>

      {/* Always-on services */}
      <div>
        <p className="text-xs font-medium text-gray-500 uppercase tracking-wider mb-2">
          Always enabled
        </p>
        <div className="space-y-1.5">
          {ALWAYS_ON_SERVICES.map(svc => (
            <div
              key={svc.key}
              className="flex items-center gap-3 p-3 rounded-lg border border-gray-800 bg-gray-900/40 opacity-60"
            >
              <input type="checkbox" checked readOnly disabled className="mt-0 accent-blue-500" aria-label={`${svc.label} is always enabled`} />
              <span className="text-sm text-gray-400">{svc.label}</span>
              <span className="ml-auto text-xs text-gray-600">always enabled</span>
            </div>
          ))}
        </div>
      </div>

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

function Step6Timezone({ 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={6}
        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>
  );
}

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 Step7Review({ fields, onBack, onSubmit, submitting, submitError }) {
  const domainLabel = DOMAIN_OPTIONS.find(o => o.value === fields.domain_type)?.label || fields.domain_type;
  const ddnsLabel = DDNS_OPTIONS.find(o => o.value === fields.ddns_provider)?.label || fields.ddns_provider;
  const serviceLabels = fields.services.length
    ? fields.services.map(k => OPTIONAL_SERVICES.find(s => s.key === k)?.label || k).join(', ')
    : 'None selected';

  return (
    <div>
      <StepHeader
        step={7}
        title="Review and finish"
        description="Check your choices below. You can go back to change anything before completing setup."
      />
      <div className="bg-gray-800/50 border border-gray-700 rounded-lg px-4 py-1 mb-2">
        <ReviewRow label="Cell name" value={fields.cell_name} />
        <ReviewRow label="Admin password" value="••••••••••••" />
        <ReviewRow label="Domain type" value={domainLabel} />
        {fields.domain_type !== 'lan_only' && (
          <ReviewRow label="DDNS provider" value={ddnsLabel} />
        )}
        <ReviewRow label="Optional services" value={serviceLabels} />
        <ReviewRow label="Timezone" value={fields.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);

  // Form state
  const [cellName, setCellName] = useState('');
  const [password, setPassword] = useState('');
  const [passwordConfirm, setPasswordConfirm] = useState('');
  const [domainType, setDomainType] = useState('pic_ngo');
  const [ddnsProvider, setDdnsProvider] = useState('pic_ngo');
  const [services, setServices] = useState(['email', 'calendar', 'files', 'webmail']);
  const [timezone, setTimezone] = useState(
    (() => { try { return Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC'; } catch { return 'UTC'; } })()
  );

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

  const skipDdns = domainType === 'lan_only';

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

  // Skip step 4 when LAN only
  const handleStep3Next = () => {
    if (skipDdns) setStep(5);
    else setStep(4);
  };
  const handleStep4Back = () => setStep(3);
  const handleStep5Back = () => {
    if (skipDdns) setStep(3);
    else setStep(4);
  };

  const handleSubmit = async () => {
    setSubmitError('');
    setSubmitting(true);
    const payload = {
      cell_name: cellName,
      password,
      domain_type: domainType,
      ...(skipDdns ? {} : { ddns_provider: ddnsProvider }),
      services,
      timezone,
    };
    try {
      await setupAPI.complete(payload);
      setDone(true);
      setTimeout(() => navigate('/login', { replace: true }), 2000);
    } catch (e) {
      setSubmitError(
        e?.response?.data?.error ||
        'Setup could not be completed. Please check your entries and try again.'
      );
    } finally {
      setSubmitting(false);
    }
  };

  const allFields = { cell_name: cellName, domain_type: domainType, ddns_provider: ddnsProvider, services, timezone };

  if (done) {
    return (
      <div className="flex items-center justify-center min-h-screen bg-gray-950">
        <div className="text-center">
          <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>
          <p className="text-sm text-gray-400">Redirecting to login...</p>
        </div>
      </div>
    );
  }

  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">
        {/* Page title */}
        <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 && (
          <Step1CellName value={cellName} onChange={setCellName} onNext={goNext} />
        )}
        {step === 2 && (
          <Step2Password
            password={password}
            confirm={passwordConfirm}
            onChangePassword={setPassword}
            onChangeConfirm={setPasswordConfirm}
            onNext={goNext}
            onBack={goBack}
          />
        )}
        {step === 3 && (
          <Step3Domain value={domainType} onChange={setDomainType} onNext={handleStep3Next} onBack={goBack} />
        )}
        {step === 4 && (
          <Step4DDNS value={ddnsProvider} onChange={setDdnsProvider} onNext={goNext} onBack={handleStep4Back} />
        )}
        {step === 5 && (
          <Step5Services selected={services} onChange={setServices} onNext={goNext} onBack={handleStep5Back} />
        )}
        {step === 6 && (
          <Step6Timezone value={timezone} onChange={setTimezone} onNext={goNext} onBack={goBack} />
        )}
        {step === 7 && (
          <Step7Review
            fields={allFields}
            onBack={goBack}
            onSubmit={handleSubmit}
            submitting={submitting}
            submitError={submitError}
          />
        )}
      </div>
    </div>
  );
}
