'use client';

import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';
import Cookies from 'js-cookie';
import { motion } from 'framer-motion';
import { toast } from 'react-toastify';
import { api } from '@/lib/api';
import SearchableSelect from '@/components/SearchableSelect';
import LocationAsyncSelect from '@/components/LocationAsyncSelect';
import { ResumePreviewModal } from '@/components/ResumePreviewModal';

interface FormState {
  first_name: string; last_name: string; email: string; phone_number: string;
  country: string; state: string; city: string; preferred_location: string;
  highest_qualification: string; language: string; notice_period_id: string; expected_ctc: string;
  fresher: boolean; total_experience: string; current_company: string;
  current_role: string; current_ctc: string;
  skills: string; professional_summary: string; resume: string | null;
  gender: string; permanent_address: string; current_address: string;
}

const EMPTY: FormState = {
  first_name: '', last_name: '', email: '', phone_number: '', country: '', state: '', city: '',
  preferred_location: '', highest_qualification: '', language: '', notice_period_id: '', expected_ctc: '',
  fresher: true, total_experience: '', current_company: '', current_role: '', current_ctc: '',
  skills: '', professional_summary: '', resume: null, gender: '', permanent_address: '', current_address: '',
};

const QUALIFICATIONS = ['10th', '12th', 'BA', 'MA', 'Btech', 'Mtech', 'MBA', 'Graduate', 'Post Graduate', 'Diploma'];

// Annual CTC is entered as Lakhs + Thousands instead of a free number, e.g.
// 12 Lakhs + 50 Thousand = ₹12,50,000.
const LAKHS_OPTIONS = Array.from({ length: 50 }, (_, i) => String(i + 1));       // 1..50
const THOUSANDS_OPTIONS = Array.from({ length: 99 }, (_, i) => String(i + 1));   // 1..99
/** Stored CTC (rupees) -> the Lakhs/Thousands dropdown values that produced it. */
const splitCtc = (v: unknown): { lakhs: string; thousands: string } => {
  const n = Number(v);
  if (!v || !Number.isFinite(n) || n <= 0) return { lakhs: '', thousands: '' };
  const lakhs = Math.floor(n / 100000);
  const thousands = Math.floor((n % 100000) / 1000);
  return { lakhs: lakhs ? String(lakhs) : '', thousands: thousands ? String(thousands) : '' };
};
/** Lakhs/Thousands dropdown values -> the stored CTC (rupees) as a string. */
const combineCtc = (lakhs: string, thousands: string): string => {
  const total = (Number(lakhs) || 0) * 100000 + (Number(thousands) || 0) * 1000;
  return total > 0 ? String(total) : '';
};

type Opt = { id: number; name: string };
const filled = (v: unknown) => v !== null && v !== undefined && String(v).trim() !== '';
const toCsv = (arr: string[]) => arr.filter(Boolean).join(', ');
const fromCsv = (s: string) => (s ? s.split(',').map((x) => x.trim()).filter(Boolean) : []);
// DRF error payloads can nest arbitrarily — walk the whole structure instead of
// assuming one flat level, or a nested dict/list renders as "[object Object]".
function flattenErrors(e: any): string[] {
  if (e == null) return [];
  if (typeof e === 'string') return [e];
  if (Array.isArray(e)) return e.flatMap(flattenErrors);
  if (typeof e === 'object') return Object.values(e).flatMap(flattenErrors);
  return [String(e)];
}

// Contact number: exactly 10 digits, nothing else.
const PHONE_LENGTH = 10;
const onlyDigits = (v: string) => (v || '').replace(/\D/g, '').slice(0, PHONE_LENGTH);
const isValidPhone = (v: string) => new RegExp(`^\\d{${PHONE_LENGTH}}$`).test((v || '').trim());
/** Normalise an inbound value (parsed résumé, legacy DB row) to bare digits.
 *  Over-long values keep the LAST 10 digits, so a country code like +91 or a
 *  leading 0 is dropped rather than truncating the actual subscriber number. */
const normalizePhone = (v: unknown) => {
  const digits = String(v ?? '').replace(/\D/g, '');
  return digits.length > PHONE_LENGTH ? digits.slice(-PHONE_LENGTH) : digits;
};

function requiredChecks(f: FormState): { label: string; ok: boolean }[] {
  const base = [
    { label: 'Candidate name', ok: filled(f.first_name) && filled(f.last_name) },
    // Must be a complete 10-digit number, not merely non-empty, so the progress
    // ring and the submit gate agree with the field-level validation.
    { label: 'Contact no. (10 digits)', ok: isValidPhone(f.phone_number) },
    { label: 'Email', ok: filled(f.email) },
    { label: 'Country', ok: filled(f.country) },
    { label: 'State', ok: filled(f.state) },
    { label: 'City', ok: filled(f.city) },
    { label: 'Gender', ok: filled(f.gender) },
    { label: 'Current address', ok: filled(f.current_address) },
    { label: 'Permanent address', ok: filled(f.permanent_address) },
    { label: 'Qualification', ok: filled(f.highest_qualification) },
    { label: 'Desired pay', ok: filled(f.expected_ctc) },
    { label: 'Notice period', ok: filled(f.notice_period_id) },
    { label: 'Work experience', ok: f.fresher || filled(f.total_experience) },
  ];
  if (!f.fresher) {
    base.push(
      { label: 'Current employer', ok: filled(f.current_company) },
      { label: 'Designation', ok: filled(f.current_role) },
      { label: 'Annual salary', ok: filled(f.current_ctc) },
    );
  }
  return base;
}

export default function ProfileCompletionModal() {
  const router = useRouter();
  const [form, setForm] = useState<FormState>(EMPTY);
  const [resumeFile, setResumeFile] = useState<File | null>(null);
  // Signed, short-lived link to the résumé already on file (résumés live in
  // private storage, so the bare `resume` path is NOT directly viewable).
  const [resumeUrl, setResumeUrl] = useState<string | null>(null);
  const [open, setOpen] = useState(false);
  const [saving, setSaving] = useState(false);
  const [errors, setErrors] = useState<string[]>([]);
  const [previewModalOpen, setPreviewModalOpen] = useState(false);

  const [countries, setCountries] = useState<Opt[]>([]);
  const [states, setStates] = useState<Opt[]>([]);
  const [cities, setCities] = useState<Opt[]>([]);
  const [allCities, setAllCities] = useState<Opt[]>([]);
  const [countryId, setCountryId] = useState<number | null>(null);
  const [stateId, setStateId] = useState<number | null>(null);
  const [skillOptions, setSkillOptions] = useState<{ value: string; label: string }[]>([]);
  const [eduOptions, setEduOptions] = useState<{ value: string; label: string }[]>([]);
  const [noticeOpts, setNoticeOpts] = useState<{ value: string; label: string }[]>([]);
  const [langOpts, setLangOpts] = useState<{ value: string; label: string }[]>([]);
  const [desigOpts, setDesigOpts] = useState<{ value: string; label: string }[]>([]);
  // Desired pay / Annual salary, entered as Lakhs + Thousands (see splitCtc/combineCtc).
  const [expLakhs, setExpLakhs] = useState('');
  const [expThousands, setExpThousands] = useState('');
  const [curLakhs, setCurLakhs] = useState('');
  const [curThousands, setCurThousands] = useState('');


  const listOf = (res: any): any[] => {
    const d = res?.data ?? res;
    return Array.isArray(d) ? d : (d?.results ?? []);
  };



  useEffect(() => {
    (async () => {
      let p: any = {};
      try { p = (await api.get('/candidates/me/') as any)?.data ?? {}; }
      catch (e: any) {
        // 401/403/404 → this user simply isn't a candidate; skip quietly.
        // Anything else is a real problem the candidate should know about.
        if (e?.status && ![401, 403, 404].includes(e.status)) {
          toast.error(e instanceof Error ? e.message : 'Could not load your profile. Please refresh.');
        }
      }

      // Résumé-parsed values stashed at registration. Accuracy-first: the parser
      // only includes fields it was confident about; low-confidence ones are
      // absent/blank. We use these ONLY to fill fields the saved profile leaves
      // empty — never to overwrite a real value or the user's own edits.
      let parsed: any = {};
      try {
        const raw = sessionStorage.getItem('resume_parsed_profile');
        if (raw) parsed = JSON.parse(raw) || {};
      } catch { /* unavailable/corrupt — no pre-fill */ }
      const pf = (dbVal: any, parsedVal: any) => (filled(dbVal) ? dbVal : (filled(parsedVal) ? parsedVal : ''));

      const names = Array.isArray(p.skills) ? p.skills.map((s: any) => s?.name ?? s).filter(Boolean) : [];
      const langNames = Array.isArray(p.languages) ? p.languages.map((l: any) => l?.name ?? l).filter(Boolean) : [];
      // Résumé shows work experience → not a fresher (only when the DB hasn't
      // recorded an explicit choice yet, i.e. still the default `true`).
      const parsedHasExp = filled(parsed.current_company) || filled(parsed.current_role) || filled(parsed.total_experience);
      const next: FormState = {
        first_name: pf(p.first_name, parsed.first_name), last_name: pf(p.last_name, parsed.last_name), email: p.email || '',
        // A parsed résumé (or legacy DB row) can carry "+91 98765-43210" etc.
        // Normalise to bare digits so the field's own rules are never violated
        // by pre-filled data — otherwise the modal could never be completed.
        phone_number: normalizePhone(pf(p.phone_number, parsed.phone_number)),
        country: pf(p.country, parsed.country), state: pf(p.state, parsed.state), city: pf(p.city, parsed.city),
        language: toCsv(langNames),
        preferred_location: p.preferred_location || '', highest_qualification: pf(p.highest_qualification, parsed.highest_qualification),
        notice_period_id: p.notice_period_id != null ? String(p.notice_period_id) : '', expected_ctc: p.expected_ctc ?? '',
        fresher: p.fresher === false ? false : (parsedHasExp ? false : (p.fresher ?? true)),
        total_experience: pf(p.total_experience, parsed.total_experience), current_company: pf(p.current_company, parsed.current_company),
        current_role: pf(p.current_role, parsed.current_role), current_ctc: p.current_ctc ?? '',
        skills: names.join(', '), professional_summary: pf(p.professional_summary, parsed.professional_summary), resume: p.resume ?? null,
        gender: pf(p.gender, parsed.gender), permanent_address: pf(p.permanent_address, parsed.permanent_address),
        current_address: pf(p.current_address, parsed.current_address),
      };
      setForm(next);
      // Pre-fill the Lakhs/Thousands dropdowns from whatever CTC was already saved.
      const eSplit = splitCtc(next.expected_ctc);
      const cSplit = splitCtc(next.current_ctc);
      setExpLakhs(eSplit.lakhs); setExpThousands(eSplit.thousands);
      setCurLakhs(cSplit.lakhs); setCurThousands(cSplit.thousands);
      // Signed link to the résumé uploaded at registration, so it can be previewed here.
      setResumeUrl(p.resume_url ?? null);
      if (requiredChecks(next).some((c) => !c.ok)) setOpen(true);

      // Skills master (public endpoint — accessible to candidates)
      try {
        const sk = listOf(await api.get('/public/skills/'));
        setSkillOptions(sk.map((s: any) => ({ value: s.name, label: s.name })));
        // Pre-fill parsed skills, but only those present in the master list —
        // free-text skills would fail the on-submit validation. Only when the
        // saved profile has none yet.
        if (!next.skills && parsed.skills) {
          const known = new Map(sk.map((s: any) => [String(s.name).toLowerCase(), s.name]));
          const chosen = fromCsv(String(parsed.skills)).map((s) => known.get(s.toLowerCase())).filter(Boolean);
          if (chosen.length) setForm((f) => (f.skills ? f : { ...f, skills: chosen.join(', ') }));
        }
      } catch { /* leave creatable-only */ }

      // Notice periods master data
      try {
        const nps = listOf(await api.get('/public/notice-periods/'));
        if (nps.length) {
          setNoticeOpts(nps.map((n: any) => ({ value: String(n.id), label: n.label })));
        }
      } catch { }
      // Languages master data
      try {
        const langs = listOf(await api.get('/public/languages/'));
        if (langs.length) {
          setLangOpts(langs.map((l: any) => ({ value: l.name, label: l.name })));
          // Pre-fill every parsed language that exists in the master list.
          if (!next.language && parsed.languages) {
            const byLower = new Map(langs.map((l: any) => [String(l.name).toLowerCase(), l.name]));
            const matches = fromCsv(String(parsed.languages)).map((l) => byLower.get(l.toLowerCase())).filter(Boolean);
            if (matches.length) setForm((f) => (f.language ? f : { ...f, language: toCsv(matches as string[]) }));
          }
        }
      } catch { }
      // Designations master data
      try {
        const dgs = listOf(await api.get('/public/designations/'));
        if (dgs.length) {
          setDesigOpts(dgs.map((d: any) => ({ value: d.name, label: d.name })));
        }
      } catch { }


      // Education/qualification master (public); fall back to built-in list.
      try {
        const ed = listOf(await api.get('/public/educations/'));
        setEduOptions(ed.length ? ed.map((e: any) => ({ value: e.name, label: e.name }))
          : QUALIFICATIONS.map((q) => ({ value: q, label: q })));
      } catch { setEduOptions(QUALIFICATIONS.map((q) => ({ value: q, label: q }))); }

      if (!next.country) {
        setForm((f) => ({ ...f, country: 'India' }));
      }

      // One-shot: the parsed values have now been applied to the form, so
      // clear the stash — a later manual re-open shouldn't re-apply them.
      try { sessionStorage.removeItem('resume_parsed_profile'); } catch { }
    })();
  }, []);

  const set = (k: keyof FormState, v: any) => setForm((f) => ({ ...f, [k]: v }));

  const onCountry = (name: string) => {
    setForm((f) => ({ ...f, country: name, state: '', city: '' }));
    setStateId(null);
  };
  const onState = (name: string) => {
    setForm((f) => ({ ...f, state: name, city: '' }));
  };

  // Clean display name for the résumé already on file. Stored paths look like
  // ".../<uuid>__resume.pdf" — strip the directory and the uuid prefix.
  const resumeName = typeof form.resume === 'string' && form.resume
    ? decodeURIComponent((form.resume.split('/').pop() || '').split('__').pop() || '')
    : '';

  const checks = requiredChecks(form);
  const pending = checks.filter((c) => !c.ok).map((c) => c.label);
  const pct = Math.round((checks.filter((c) => c.ok).length / checks.length) * 100);
  const complete = pending.length === 0;

  const submit = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!complete) { setErrors([`Please fill all required fields: ${pending.join(', ')}.`]); return; }
    if (!isValidPhone(form.phone_number)) {
      setErrors([`Contact no. must be exactly ${PHONE_LENGTH} digits, with no letters or special characters.`]);
      return;
    }
    // Belt-and-braces: the input already strips "-", but guard here too since
    // the backend also rejects negative experience.
    if (!form.fresher && form.total_experience && Number(form.total_experience) < 0) {
      setErrors(['Total experience cannot be negative.']);
      return;
    }
    const knownSkills = new Set(skillOptions.map((o) => o.value));
    const invalidSkills = fromCsv(form.skills).filter((s) => !knownSkills.has(s));
    if (invalidSkills.length) {
      setErrors([`Please pick key skills from the suggested list — remove: ${invalidSkills.join(', ')}.`]);
      return;
    }
    setErrors([]); setSaving(true);
    try {
      const payload: any = {
        first_name: form.first_name, last_name: form.last_name, phone_number: form.phone_number,
        country: form.country, state: form.state, city: form.city,
        current_location: form.city,  // keep the legacy field in sync with City
        preferred_location: form.preferred_location,
        highest_qualification: form.highest_qualification, notice_period_id: form.notice_period_id ? Number(form.notice_period_id) : null,
        expected_ctc: form.expected_ctc, fresher: form.fresher,
        professional_summary: form.professional_summary, skills: fromCsv(form.skills),
        languages: fromCsv(form.language),
        gender: form.gender, permanent_address: form.permanent_address, current_address: form.current_address,
      };
      if (!form.fresher) {
        payload.total_experience = form.total_experience;
        payload.current_company = form.current_company;
        payload.current_role = form.current_role;
        payload.current_ctc = form.current_ctc;
      }
      await api.patch('/candidates/me/', payload);
      if (resumeFile) { const fd = new FormData(); fd.append('resume', resumeFile); await api.uploadPatch('/candidates/me/', fd); }
      toast.success('Profile completed. Thank you!');
      setOpen(false);
    } catch (err: any) {
      const data = err?.data?.errors;
      const messages = data ? flattenErrors(data) : [];
      setErrors(messages.length ? messages : [err?.data?.message || 'Could not save. Please try again.']);
      toast.error('Please fix the highlighted issues.');
    } finally { setSaving(false); }
  };

  const logout = () => { Cookies.remove('access_token'); Cookies.remove('refresh_token'); router.push('/login'); };

  if (!open) return null;

  const circ = 2 * Math.PI * 15.9;
  const inputCls = 'w-full px-3 py-2 text-sm border border-slate-300 dark:border-slate-700 bg-white dark:bg-slate-900 rounded-none focus:outline-none focus:border-[#405189]';
  const Lbl = ({ t, req }: { t: string; req?: boolean }) => (
    <label className="block text-[11px] font-bold uppercase tracking-wide text-slate-500 mb-1">{t}{req && <span className="text-rose-500 ml-0.5">*</span>}</label>
  );
  const F = ({ label, k, type = 'text', required, readOnly }: { label: string; k: keyof FormState; type?: string; required?: boolean; readOnly?: boolean }) => (
    <div>
      <Lbl t={label} req={required} />
      <input type={type} value={(form[k] ?? '') as string} onChange={(e) => set(k, e.target.value)} readOnly={readOnly}
        className={`${inputCls} ${readOnly ? 'bg-slate-100 dark:bg-slate-800 text-slate-500' : ''}`} />
    </div>
  );
  const Sel = ({ label, k, options, required, placeholder = 'Select…' }: { label: string; k: keyof FormState; options: { value: string; label: string }[]; required?: boolean; placeholder?: string }) => {
    const cur = String(form[k] ?? '');
    const known = options.some((o) => o.value === cur);
    return (
      <div>
        <Lbl t={label} req={required} />
        <select value={cur} onChange={(e) => set(k, e.target.value)} className={inputCls}>
          <option value="">{placeholder}</option>
          {cur && !known && <option value={cur}>{cur} (current)</option>}
          {options.map((o) => <option key={o.value} value={o.value}>{o.label}</option>)}
        </select>
      </div>
    );
  };

  return (
    <div className="fixed inset-0 z-[60] flex items-start justify-center bg-black/60 p-4 overflow-y-auto">
      <motion.div initial={{ opacity: 0, y: 16 }} animate={{ opacity: 1, y: 0 }}
        className="w-full max-w-6xl my-6 bg-white dark:bg-slate-900 shadow-2xl border border-slate-200 dark:border-slate-800">
        <div className="flex items-center gap-4 p-5 text-white relative" style={{ background: 'linear-gradient(135deg,#405189 0%,#23b7e5 100%)' }}>
          <div className="relative w-16 h-16 shrink-0">
            <svg viewBox="0 0 36 36" className="rotate-[-90deg]">
              <circle cx="18" cy="18" r="15.9" fill="none" stroke="rgba(255,255,255,0.25)" strokeWidth="3" />
              <motion.circle cx="18" cy="18" r="15.9" fill="none" stroke="#fff" strokeWidth="3" strokeLinecap="round"
                strokeDasharray={circ} animate={{ strokeDashoffset: circ - (circ * pct) / 100 }} transition={{ duration: 0.5 }} />
            </svg>
            <div className="absolute inset-0 flex items-center justify-center font-black text-sm">{pct}%</div>
          </div>
          <div className="flex-1">
            <h2 className="text-lg font-black">Complete your profile to continue</h2>
            <p className="text-xs text-white/85 mt-0.5">Required before you can browse and apply. Closes only when all required (*) fields are saved.</p>
          </div>
          <button type="button" onClick={() => complete && setOpen(false)} disabled={!complete}
            title={complete ? 'Close' : 'Fill all required fields to close'}
            className={`absolute top-3 right-3 w-7 h-7 flex items-center justify-center text-white/90 ${complete ? 'hover:bg-white/20 cursor-pointer' : 'opacity-40 cursor-not-allowed'}`}>
            <i className="fa-solid fa-xmark" />
          </button>
        </div>

        <form onSubmit={submit} className="p-5">
          {errors.length > 0 && (
            <div className="mb-4 p-3 bg-rose-50 border border-rose-200 text-rose-700 text-xs space-y-0.5">
              {errors.map((e, i) => <div key={i}>• {e}</div>)}
            </div>
          )}

          {/* Résumé upload — kept at the top so a résumé uploaded during
              registration is shown first and its parsed values pre-fill the
              fields below. */}
          <div className="mb-3">
            <Lbl t="Résumé (PDF/DOCX)" />
            <div className="flex items-center gap-3">
              {form.resume && !resumeFile && resumeName && (
                <span className="text-xs text-emerald-600 font-semibold whitespace-nowrap max-w-[45%] truncate" title={resumeName}>
                  <i className="fa-solid fa-circle-check mr-1" />{resumeName}
                </span>
              )}
              <input type="file" accept=".pdf,.doc,.docx" onChange={(e) => setResumeFile(e.target.files?.[0] ?? null)}
                className="block w-full text-sm text-slate-600 file:mr-3 file:py-1.5 file:px-3 file:border-0 file:bg-[#405189] file:text-white file:font-bold file:text-xs" />
              {(resumeFile || resumeUrl || (typeof form.resume === 'string' && form.resume)) && (
                <button
                  type="button"
                  onClick={() => setPreviewModalOpen(true)}
                  className="shrink-0 px-3 py-1.5 bg-[#405189]/10 text-[#405189] dark:bg-indigo-950/50 dark:text-indigo-300 hover:bg-[#405189]/20 border border-[#405189]/30 text-xs font-bold transition flex items-center gap-1.5 cursor-pointer"
                >
                  <i className="fa-solid fa-eye" />
                  Preview
                </button>
              )}
            </div>
          </div>

          <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
            {F({ label: 'First name', k: 'first_name', required: true })}
            {F({ label: 'Last name', k: 'last_name', required: true })}
            <div>
              <Lbl t="Contact no." req />
              {/* Digits only, hard-capped at 10. onChange is the real enforcement
                  (it also covers paste, drag-drop and autofill, which fire input
                  events); onKeyDown just stops the keystroke from flickering.
                  type=number is avoided deliberately — it accepts "e", "+", "-"
                  and shows spinners. */}
              <input
                type="text"
                inputMode="numeric"
                autoComplete="tel"
                maxLength={PHONE_LENGTH}
                placeholder="10-digit mobile number"
                value={form.phone_number ?? ''}
                onChange={(e) => set('phone_number', onlyDigits(e.target.value))}
                onKeyDown={(e) => {
                  // Block the characters type=text would otherwise accept, while
                  // leaving navigation/editing keys and shortcuts alone.
                  if (e.ctrlKey || e.metaKey || e.altKey || e.key.length > 1) return;
                  if (!/\d/.test(e.key)) e.preventDefault();
                }}
                className={`${inputCls} ${form.phone_number && !isValidPhone(form.phone_number)
                    ? 'border-rose-400 focus:border-rose-500'
                    : ''
                  }`}
              />
              {form.phone_number && !isValidPhone(form.phone_number) && (
                <p className="mt-1 text-[11px] font-semibold text-rose-500">
                  Enter exactly {PHONE_LENGTH} digits ({form.phone_number.length}/{PHONE_LENGTH}).
                </p>
              )}
            </div>
            {F({ label: 'Email', k: 'email', readOnly: true, required: true })}
          </div>

          {/* Cascading location */}
          <div className="grid grid-cols-1 sm:grid-cols-3 gap-3 mt-3">
            <div>
              <Lbl t="Country" req />
              <LocationAsyncSelect
                locationType="country"
                value={form.country}
                onChange={(val, option) => {
                  const opt = Array.isArray(option) ? option[0] : option;
                  const cname = opt?.name || (typeof val === 'string' ? val : '');
                  const cid = opt?.id ? Number(opt.id) : null;
                  setCountryId(cid);
                  setStateId(null);
                  setForm((f) => ({ ...f, country: cname, state: '', city: '' }));
                }}
              />
            </div>
            <div>
              <Lbl t="State" req />
              <LocationAsyncSelect
                locationType="state"
                countryId={countryId}
                value={form.state}
                onChange={(val, option) => {
                  const opt = Array.isArray(option) ? option[0] : option;
                  const sname = opt?.name || (typeof val === 'string' ? val : '');
                  const sid = opt?.id ? Number(opt.id) : null;
                  setStateId(sid);
                  setForm((f) => ({ ...f, state: sname, city: '' }));
                }}
              />
            </div>
            <div>
              <Lbl t="City" req />
              <LocationAsyncSelect
                locationType="city"
                countryId={countryId}
                stateId={stateId}
                value={form.city}
                onChange={(val, option) => {
                  const opt = Array.isArray(option) ? option[0] : option;
                  const cname = opt?.name || (typeof val === 'string' ? val : '');
                  setForm((f) => ({ ...f, city: cname }));
                }}
              />
            </div>
          </div>

          {/* Gender, Current Address, and Permanent Address */}
          <div className="grid grid-cols-1 sm:grid-cols-3 gap-3 mt-3">
            <div>
              <Lbl t="Gender" req />
              <select value={form.gender} onChange={(e) => set('gender', e.target.value)} className={inputCls}>
                <option value="">Select gender</option>
                <option value="Male">Male</option>
                <option value="Female">Female</option>
                <option value="Other">Other</option>
              </select>
            </div>
            <div>
              <Lbl t="Current address" req />
              <textarea value={form.current_address} onChange={(e) => set('current_address', e.target.value)} rows={2} className={inputCls} />
            </div>
            <div>
              <Lbl t="Permanent address" req />
              <textarea value={form.permanent_address} onChange={(e) => set('permanent_address', e.target.value)} rows={2} className={inputCls} />
            </div>
          </div>

          {/* Preferred locations (multiple cities) */}
          <div className="mt-3">
            <Lbl t="Preferred locations (cities)" />
            <LocationAsyncSelect
              locationType="city"
              allowAny
              isMulti
              value={fromCsv(form.preferred_location)}
              onChange={(vals: any) => {
                const arr = (vals || []).map((v: any) => (typeof v === 'object' ? v.value : v));
                setForm((f) => ({ ...f, preferred_location: toCsv(arr) }));
              }}
              placeholder="Search preferred cities…"
            />
          </div>

          <div className="grid grid-cols-1 md:grid-cols-3 gap-4 mt-3">
            <div>
              <Lbl t="Highest qualification" req />
              <select value={form.highest_qualification} onChange={(e) => set('highest_qualification', e.target.value)} className={inputCls}>
                <option value="">Select qualification</option>
                {form.highest_qualification && !eduOptions.some((o) => o.value === form.highest_qualification) && (
                  <option value={form.highest_qualification}>{form.highest_qualification}</option>
                )}
                {eduOptions.map((o) => <option key={o.value} value={o.value}>{o.label}</option>)}
              </select>
            </div>
            <div>
              <Lbl t="Language" />
              <SearchableSelect isMulti
                options={langOpts}
                value={fromCsv(form.language)}
                onChange={(vals: any) => set('language', toCsv((vals || []).map((v: any) => (typeof v === 'object' ? v.value : v))))}
                placeholder="Select languages…" controlBgClass="bg-white dark:bg-slate-900" />
            </div>
            <div>
              <Lbl t="Desired pay (annual)" req />
              <div className="grid grid-cols-2 gap-2">
                <select value={expLakhs} onChange={(e) => { const l = e.target.value; setExpLakhs(l); set('expected_ctc', combineCtc(l, expThousands)); }} className={inputCls}>
                  <option value="">Lakhs</option>
                  {LAKHS_OPTIONS.map((n) => <option key={n} value={n}>{n} Lakh{n === '1' ? '' : 's'}</option>)}
                </select>
                <select value={expThousands} onChange={(e) => { const t = e.target.value; setExpThousands(t); set('expected_ctc', combineCtc(expLakhs, t)); }} className={inputCls}>
                  <option value="">Thousands</option>
                  {THOUSANDS_OPTIONS.map((n) => <option key={n} value={n}>{n} Thousand{n === '1' ? '' : 's'}</option>)}
                </select>
              </div>
            </div>
            {Sel({ label: 'Notice period', k: 'notice_period_id', options: noticeOpts, required: true, placeholder: 'Select notice period' })}
          </div>

          <label className="flex items-center gap-2 mt-4 text-sm font-semibold text-slate-700 dark:text-slate-200 cursor-pointer">
            <input type="checkbox" checked={form.fresher} onChange={(e) => set('fresher', e.target.checked)} className="w-4 h-4 accent-[#405189]" />
            I am a fresher (no work experience)
          </label>

          {!form.fresher && (
            <div className="grid grid-cols-1 md:grid-cols-3 gap-4 mt-3">
              <div>
                <Lbl t="Total experience (years)" req />
                {/* type=number alone doesn't block "-"; we also strip it on
                    change and swallow the keystroke so negative experience
                    can't be entered at all (backend rejects it too). */}
                <input
                  type="number"
                  min={0}
                  step={0.1}
                  inputMode="decimal"
                  value={form.total_experience ?? ''}
                  onChange={(e) => set('total_experience', e.target.value.replace(/-/g, ''))}
                  onKeyDown={(e) => { if (e.key === '-' || e.key === 'e' || e.key === '+') e.preventDefault(); }}
                  className={inputCls}
                />
              </div>
              {F({ label: 'Current employer', k: 'current_company', required: true })}
              <div>
                <Lbl t="Designation" req />
                <select value={form.current_role} onChange={(e) => set('current_role', e.target.value)} className={inputCls}>
                  <option value="">Select designation</option>
                  {form.current_role && !desigOpts.some((o) => o.value === form.current_role) && (
                    <option value={form.current_role}>{form.current_role}</option>
                  )}
                  {desigOpts.map((o) => <option key={o.value} value={o.value}>{o.label}</option>)}
                </select>
              </div>
              <div>
                <Lbl t="Annual salary (current)" req />
                <div className="grid grid-cols-2 gap-2">
                  <select value={curLakhs} onChange={(e) => { const l = e.target.value; setCurLakhs(l); set('current_ctc', combineCtc(l, curThousands)); }} className={inputCls}>
                    <option value="">Lakhs</option>
                    {LAKHS_OPTIONS.map((n) => <option key={n} value={n}>{n} Lakh{n === '1' ? '' : 's'}</option>)}
                  </select>
                  <select value={curThousands} onChange={(e) => { const t = e.target.value; setCurThousands(t); set('current_ctc', combineCtc(curLakhs, t)); }} className={inputCls}>
                    <option value="">Thousands</option>
                    {THOUSANDS_OPTIONS.map((n) => <option key={n} value={n}>{n} Thousand{n === '1' ? '' : 's'}</option>)}
                  </select>
                </div>
              </div>
            </div>
          )}

          {/* Key skills — master data, multi-select */}
          <div className="mt-3">
            <Lbl t="Key skills" />
            <SearchableSelect isMulti
              options={skillOptions}
              value={fromCsv(form.skills)}
              onChange={(vals: any) => set('skills', toCsv((vals || []).map((v: any) => (typeof v === 'object' ? v.value : v))))}
              placeholder="Select skills…" controlBgClass="bg-white dark:bg-slate-900" />
          </div>

          {previewModalOpen && (resumeFile || resumeUrl || form.resume) && (
            <ResumePreviewModal
              url={resumeFile ? URL.createObjectURL(resumeFile) : (resumeUrl || (typeof form.resume === 'string' ? form.resume : null))}
              name={resumeFile ? resumeFile.name : (typeof form.resume === 'string' && form.resume ? decodeURIComponent(form.resume.split('/').pop() || 'Résumé') : 'Résumé')}
              onClose={() => setPreviewModalOpen(false)}
            />
          )}

          {pending.length > 0 && (
            <p className="text-[11px] text-slate-400 mt-3">Still required: <span className="font-semibold text-rose-500">{pending.join(', ')}</span></p>
          )}

          <div className="flex items-center justify-between mt-5 gap-3">
            <button type="button" onClick={logout} className="text-xs font-semibold text-slate-400 hover:text-slate-600">Log out</button>
            <button type="submit" disabled={saving || !complete} title={complete ? '' : 'Fill all required (*) fields first'}
              className="px-8 py-2.5 bg-[#405189] text-white font-bold text-sm hover:bg-[#334267] transition disabled:opacity-50 disabled:cursor-not-allowed">
              {saving ? 'Saving…' : 'Save & close'}
            </button>
          </div>
        </form>
      </motion.div>
    </div>
  );
}
