'use client';

import { useEffect, useRef, useState } from 'react';
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';
import { ResumeUploadConfirmModal } from '@/components/ResumeUploadConfirmModal';

type Opt = { id: number; name: string };
const csvToArr = (s: string) => (s ? s.split(',').map((x) => x.trim()).filter(Boolean) : []);
const arrToCsv = (a: string[]) => a.filter(Boolean).join(', ');

// 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) : '';
};
// DRF error payloads can nest arbitrarily (e.g. {experiences: [{joining_date: ["..."]}]}
// for many=True nested serializers) — walk the whole structure instead of assuming
// one flat level, or a nested dict/list renders as the literal string "[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)];
}

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] text-slate-800 dark:text-white';

// Red outline for a required field that was left empty on save. Inline style
// wins over the border utility in inputCls regardless of CSS order.
const errStyle = { borderColor: '#ef4444' } as const;
const errRing = 'ring-1 ring-red-400/40';

function Field({ label, value, onChange, type = 'text', readOnly = false, required = false, error = false }: {
  label: string; value: any; onChange?: (v: string) => void; type?: string; readOnly?: boolean; required?: boolean; error?: boolean;
}) {
  // Applies to every numeric Field (passing year, percentage/CGPA, …): "-" is
  // stripped on change and swallowed on keydown so a negative value can never
  // be entered, not just flagged after the fact.
  const isNumber = type === 'number';
  return (
    <div>
      <label className="block text-[11px] font-bold uppercase tracking-wide text-slate-500 mb-1">
        {label} {required && <span className="text-red-500 font-bold">*</span>}
      </label>
      <input type={type} value={value ?? ''} readOnly={readOnly}
        min={isNumber ? 0 : undefined}
        onChange={(e) => onChange?.(isNumber ? e.target.value.replace(/-/g, '') : e.target.value)}
        onKeyDown={isNumber ? (e) => { if (e.key === '-' || e.key === 'e' || e.key === '+') e.preventDefault(); } : undefined}
        style={error ? errStyle : undefined}
        className={`${inputCls} ${readOnly ? 'bg-slate-100 dark:bg-slate-800 text-slate-500' : ''} ${error ? errRing : ''}`} />
      {error && <p className="text-[11px] font-semibold text-red-500 mt-1">This field is required.</p>}
    </div>
  );
}


// ---- Phone number rules: exactly 10 digits, no letters or special characters.
const PHONE_LENGTH = 10;
const onlyDigits = (v: string) => (v || '').replace(/\D/g, '').slice(0, PHONE_LENGTH);
const isValidPhone = (v: any) => new RegExp(`^\\d{${PHONE_LENGTH}}$`).test(String(v ?? '').trim());
/** Normalise an inbound value (parsed résumé, existing 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 subscriber number. */
const normalizePhone = (v: any) => {
  const digits = String(v ?? '').replace(/\D/g, '');
  return digits.length > PHONE_LENGTH ? digits.slice(-PHONE_LENGTH) : digits;
};

/** Text input restricted to a 10-digit phone number.
 *
 * onChange is the real enforcement — it also covers paste, drag-drop and
 * autofill, which all fire input events. onKeyDown only stops the keystroke
 * from flickering in first. type=number is avoided deliberately: it accepts
 * "e", "+" and "-" and renders spinner arrows.
 */
function PhoneField({ label, value, onChange, required = false, error = false }: {
  label: string; value: any; onChange: (v: string) => void; required?: boolean; error?: boolean;
}) {
  const str = String(value ?? '');
  const incomplete = str.length > 0 && !isValidPhone(str);
  const showError = error || incomplete;
  return (
    <div>
      <label className="block text-[11px] font-bold uppercase tracking-wide text-slate-500 mb-1">
        {label} {required && <span className="text-red-500 font-bold">*</span>}
      </label>
      <input
        type="text"
        inputMode="numeric"
        autoComplete="tel"
        maxLength={PHONE_LENGTH}
        placeholder={`${PHONE_LENGTH}-digit mobile number`}
        value={str}
        onChange={(e) => onChange(onlyDigits(e.target.value))}
        onKeyDown={(e) => {
          // Leave 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();
        }}
        style={showError ? errStyle : undefined}
        className={`${inputCls} ${showError ? errRing : ''}`}
      />
      {incomplete ? (
        <p className="text-[11px] font-semibold text-red-500 mt-1">
          Enter exactly {PHONE_LENGTH} digits ({str.length}/{PHONE_LENGTH}).
        </p>
      ) : error ? (
        <p className="text-[11px] font-semibold text-red-500 mt-1">This field is required.</p>
      ) : null}
    </div>
  );
}


function SelectField({ label, value, onChange, options, required = false, placeholder = 'Select', error = false }: {
  label: string; value: any; onChange: (v: string) => void; options: { value: string; label: string }[]; required?: boolean; placeholder?: string; error?: boolean;
}) {
  const valStr = value !== null && value !== undefined ? String(Math.round(Number(value))) : '';
  return (
    <div>
      <label className="block text-[11px] font-bold uppercase tracking-wide text-slate-500 mb-1">
        {label} {required && <span className="text-red-500 font-bold">*</span>}
      </label>
      <select value={valStr} onChange={(e) => onChange(e.target.value)} style={error ? errStyle : undefined}
        className={`${inputCls} ${error ? errRing : ''}`}>
        <option value="">{placeholder}</option>
        {options.map((opt) => (
          <option key={opt.value} value={opt.value}>{opt.label}</option>
        ))}
      </select>
      {error && <p className="text-[11px] font-semibold text-red-500 mt-1">This field is required.</p>}
    </div>
  );
}


// Numeric ranges for the split dropdowns (unit selectors, not master data).
const YEARS = Array.from({ length: 41 }, (_, i) => i);      // 0–40
const MONTHS = Array.from({ length: 12 }, (_, i) => i);     // 0–11

/** Total experience as Years + Months → stored as decimal years (1 dp). */
function ExperienceField({ value, onChange, required = false }: {
  value: any; onChange: (v: string) => void; required?: boolean;
}) {
  const has = value !== '' && value !== null && value !== undefined;
  const total = Number(value) || 0;
  const years = has ? Math.floor(total) : '';
  const months = has ? Math.max(0, Math.min(11, Math.round((total - Math.floor(total)) * 12))) : '';
  const emit = (y: number, m: number) => onChange(String(Math.round((y + m / 12) * 10) / 10));
  return (
    <div>
      <label className="block text-[11px] font-bold uppercase tracking-wide text-slate-500 mb-1">
        Total experience {required && <span className="text-red-500 font-bold">*</span>}
      </label>
      <div className="grid grid-cols-2 gap-2">
        <select value={String(years)} onChange={(e) => emit(Number(e.target.value), Number(months) || 0)} className={inputCls}>
          <option value="">Years</option>
          {YEARS.map((y) => <option key={y} value={y}>{y} {y === 1 ? 'year' : 'years'}</option>)}
        </select>
        <select value={String(months)} onChange={(e) => emit(Number(years) || 0, Number(e.target.value))} className={inputCls}>
          <option value="">Months</option>
          {MONTHS.map((m) => <option key={m} value={m}>{m} {m === 1 ? 'month' : 'months'}</option>)}
        </select>
      </div>
    </div>
  );
}

const TABS = ['Personal Info', 'Education & Skills', 'Work Experience', 'Projects', 'References'] as const;
type Tab = typeof TABS[number];

// Required fields, in visual order. `when` gates fields that are only
// required for non-freshers. Labels are used in the "X is empty" toast.
const REQUIRED_FIELDS: { key: string; label: string; tab: Tab; when?: (f: any) => boolean }[] = [
  { key: 'first_name', label: 'First name', tab: 'Personal Info' },
  { key: 'last_name', label: 'Last name', tab: 'Personal Info' },
  { key: 'phone_number', label: 'Phone number', tab: 'Personal Info' },
  { key: 'country', label: 'Country', tab: 'Personal Info' },
  { key: 'state', label: 'State', tab: 'Personal Info' },
  { key: 'city', label: 'City', tab: 'Personal Info' },
  { key: 'highest_qualification', label: 'Highest qualification', tab: 'Education & Skills' },
  { key: 'expected_ctc', label: 'Desired pay (annual)', tab: 'Work Experience' },
  { key: 'notice_period_id', label: 'Notice period', tab: 'Work Experience' },
  { key: 'total_experience', label: 'Total experience', tab: 'Work Experience', when: (f) => !f.fresher },
  { key: 'current_company', label: 'Current employer', tab: 'Work Experience', when: (f) => !f.fresher },
  { key: 'current_role', label: 'Designation', tab: 'Work Experience', when: (f) => !f.fresher },
  { key: 'current_ctc', label: 'Annual salary (current)', tab: 'Work Experience', when: (f) => !f.fresher },
];

const isBlank = (v: any) => v === null || v === undefined || String(v).trim() === '';

export default function CandidateProfileEditor() {
  const [tab, setTab] = useState<Tab>('Personal Info');
  const [f, setF] = useState<any>({});
  const [educations, setEducations] = useState<any[]>([]);
  const [experiences, setExperiences] = useState<any[]>([]);
  const [projects, setProjects] = useState<any[]>([]);
  const [references, setReferences] = useState<any[]>([]);
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [resumeFile, setResumeFile] = useState<File | null>(null);
  const [pendingResume, setPendingResume] = useState<File | null>(null);
  const [parsing, setParsing] = useState(false);
  const [dragOver, setDragOver] = useState(false);
  const [previewOpen, setPreviewOpen] = useState(false);
  const resumeFileInputRef = useRef<HTMLInputElement>(null);

  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 | string | null>(null);
  const [stateId, setStateId] = useState<number | string | null>(null);
  const [skillOpts, setSkillOpts] = useState<{ value: string; label: string }[]>([]);
  const [eduOpts, setEduOpts] = 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 [fieldErrors, setFieldErrors] = useState<Set<string>>(new Set());

  const listOf = (r: any) => { const d = r?.data ?? r; return Array.isArray(d) ? d : (d?.results ?? []); };
  const clearErr = (k: string) =>
    setFieldErrors((prev) => { if (!prev.has(k)) return prev; const n = new Set(prev); n.delete(k); return n; });
  const set = (k: string, v: any) => { setF((p: any) => ({ ...p, [k]: v })); clearErr(k); };



  useEffect(() => {
    (async () => {
      try {
        const p = (await api.get('/candidates/me/') as any)?.data ?? {};
        const skills = Array.isArray(p.skills) ? p.skills.map((s: any) => s?.name ?? s) : [];
        const langs = Array.isArray(p.languages) ? p.languages.map((s: any) => s?.name ?? s) : [];
        setF({
          ...p,
          // Existing rows may predate the 10-digit rule (or carry a +91 prefix);
          // normalise on load so the editor never opens in an invalid state.
          phone_number: normalizePhone(p.phone_number),
          alternate_phone_number: normalizePhone(p.alternate_phone_number),
          resume: p.resume_url ?? p.resume ?? null,
          notice_period_id: p.notice_period_id != null ? String(p.notice_period_id) : '',
          skills: skills.join(', '),
          languages: langs.join(', '),
        });
        setEducations(p.educations || []); setExperiences(p.experiences || []);
        setProjects(p.projects || []); setReferences(p.references || []);
        // Pre-fill the Lakhs/Thousands dropdowns from whatever CTC was already saved.
        const eSplit = splitCtc(p.expected_ctc);
        const cSplit = splitCtc(p.current_ctc);
        setExpLakhs(eSplit.lakhs); setExpThousands(eSplit.thousands);
        setCurLakhs(cSplit.lakhs); setCurThousands(cSplit.thousands);
        try { setSkillOpts(listOf(await api.get('/public/skills/')).map((s: any) => ({ value: s.name, label: s.name }))); } catch { }
        try { setEduOpts(listOf(await api.get('/public/educations/')).map((e: any) => ({ value: e.name, label: e.name }))); } catch { }
        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 { }
        try {
          const langs = listOf(await api.get('/public/languages/'));
          if (langs.length) setLangOpts(langs.map((l: any) => ({ value: l.name, label: l.name })));
        } catch { }
        try {
          const dgs = listOf(await api.get('/public/designations/'));
          if (dgs.length) setDesigOpts(dgs.map((d: any) => ({ value: d.name, label: d.name })));
        } catch { }


      } catch { toast.error('Could not load your profile.'); }
      finally { setLoading(false); }
    })();
  }, []);

  const onCountry = (name: string) => { setF((p: any) => ({ ...p, country: name, state: '', city: '' })); clearErr('country'); setStateId(null); };
  const onState = (name: string) => { setF((p: any) => ({ ...p, state: name, city: '' })); clearErr('state'); };

  // Repeatable-row helpers
  const addRow = (setter: any, tmpl: any) => setter((r: any[]) => [...r, { ...tmpl }]);
  const updRow = (setter: any, i: number, k: string, v: any) => setter((r: any[]) => r.map((x, j) => (j === i ? { ...x, [k]: v } : x)));
  const delRow = (setter: any, i: number) => setter((r: any[]) => r.filter((_, j) => j !== i));

  // Refresh the whole form from a parse result: parsed values replace the old
  // ones, and fields the new résumé doesn't confidently contain are cleared
  // rather than kept stale. Email stays untouched (account email, read-only).
  const applyParsed = (parsed: any) => {
    const cap = (s: string) => (s ? s[0].toUpperCase() + s.slice(1).toLowerCase() : '');
    setFieldErrors(new Set()); // fields are being refilled — drop stale highlights
    setF((p: any) => ({
      ...p,
      first_name: parsed.first_name || '',
      last_name: parsed.last_name || '',
      // Parsed résumés often carry "+91 98765-43210" — strip to bare digits so
      // pre-filled data can't violate the field's own rules.
      phone_number: normalizePhone(parsed.phone_number),
      alternate_phone_number: normalizePhone(parsed.alternate_phone_number),
      date_of_birth: parsed.date_of_birth || '',
      gender: cap(parsed.gender || ''),
      country: parsed.country || '',
      state: parsed.state || '',
      city: parsed.city || '',
      current_location: parsed.current_location || '',
      current_address: parsed.current_address || '',
      permanent_address: parsed.permanent_address || '',
      linkedin: parsed.linkedin || '',
      github: parsed.github || '',
      portfolio: parsed.portfolio || '',
      personal_website: parsed.personal_website || '',
      professional_summary: parsed.professional_summary || '',
      skills: parsed.skills || '',
      languages: parsed.languages || '',
      highest_qualification: parsed.highest_qualification || '',
      university: parsed.university || '',
      college: parsed.college || '',
      passing_year: parsed.passing_year ?? '',
      percentage_cgpa: parsed.percentage_cgpa || '',
      fresher: typeof parsed.fresher === 'boolean' ? parsed.fresher : p.fresher,
      total_experience: parsed.total_experience ?? '',
      current_company: parsed.current_company || '',
      previous_company: parsed.previous_company || '',
      current_role: parsed.current_role || '',
      // Rarely stated in résumés — fill only when found, never clear.
      ...(parsed.notice_period != null ? { notice_period: parsed.notice_period } : {}),
    }));
    setEducations(Array.isArray(parsed.educations) ? parsed.educations : []);
    setExperiences(Array.isArray(parsed.experiences) ? parsed.experiences : []);
    setProjects(Array.isArray(parsed.projects) ? parsed.projects : []);
    setReferences(Array.isArray(parsed.references) ? parsed.references : []);
  };

  // Upload + two-stage parse (LLM primary, package-parser fallback), then
  // auto-fill the form. The endpoint saves the résumé immediately; if it
  // fails, fall back to the old behaviour of staging the file for Save.
  const onResumePick = async (file: File | null) => {
    if (!file) { setResumeFile(null); return; }
    setParsing(true);
    try {
      const fd = new FormData();
      fd.append('file', file);
      const res: any = await api.upload('/candidates/upload-resume/', fd);
      setResumeFile(null); // already uploaded & linked by the endpoint
      if (res?.resume_url || res?.resume_path) set('resume', res.resume_url ?? res.resume_path);
      const parsed = res?.parsed_data ?? {};
      const identifying = !!(parsed.first_name || parsed.email || parsed.phone_number);
      if (!identifying) {
        toast.warn(res?.message || 'Résumé uploaded, but details could not be read. Please fill the form manually.');
        return;
      }
      applyParsed(parsed);
      toast.success('Résumé parsed — review the auto-filled details and save.');
    } catch (err: any) {
      setResumeFile(file); // keep old flow: upload with the next Save
      toast.warn(err?.data?.detail || err?.data?.message || 'Could not parse the résumé; it will be uploaded when you save.');
    } finally { setParsing(false); }
  };

  // Drag-and-drop entry point — enforce the same allowed formats as the
  // file input's accept list, then stage the file for preview + confirmation.
  const onResumeDrop = (file: File | null) => {
    if (!file || parsing) return;
    const ext = file.name.slice(file.name.lastIndexOf('.')).toLowerCase();
    if (!['.pdf', '.doc', '.docx'].includes(ext)) {
      toast.error('Only PDF, DOC or DOCX résumés are supported.');
      return;
    }
    setPendingResume(file);
  };

  const save = async (e: React.FormEvent) => {
    e.preventDefault();
    // Required-field check: highlight every empty required field, jump to the
    // first one's tab, and name it in a toast. Nothing is saved until fixed.
    const missing = REQUIRED_FIELDS.filter((r) => (r.when ? r.when(f) : true) && isBlank(f[r.key]));
    if (missing.length) {
      setFieldErrors(new Set(missing.map((m) => m.key)));
      setTab(missing[0].tab);
      const rest = missing.length - 1;
      toast.error(
        `${missing[0].label} is empty — please fill it before saving.` +
        (rest ? ` (${rest} more required field${rest === 1 ? ' is' : 's are'} highlighted)` : '')
      );
      return;
    }
    // Phone numbers must be exactly 10 digits. Alternate phone is optional, so
    // it's only checked when the candidate has entered something.
    const badPhones: string[] = [];
    if (!isValidPhone(f.phone_number)) badPhones.push('phone_number');
    if (!isBlank(f.alternate_phone_number) && !isValidPhone(f.alternate_phone_number)) {
      badPhones.push('alternate_phone_number');
    }
    if (badPhones.length) {
      setFieldErrors(new Set(badPhones));
      setTab('Personal Info');
      toast.error(
        `${badPhones.includes('phone_number') ? 'Phone' : 'Alternate phone'} must be exactly ${PHONE_LENGTH} digits, with no letters or special characters.`
      );
      return;
    }
    setFieldErrors(new Set());
    setSaving(true);
    try {
      const payload: any = {
        first_name: f.first_name, last_name: f.last_name, phone_number: f.phone_number,
        alternate_phone_number: f.alternate_phone_number || '', date_of_birth: f.date_of_birth || null,
        gender: f.gender || '', country: f.country || '', state: f.state || '', city: f.city || '',
        current_location: f.current_location || f.city || '', preferred_location: f.preferred_location || '',
        current_address: f.current_address || '', permanent_address: f.permanent_address || '',
        fresher: !!f.fresher, notice_period_id: f.notice_period_id ? Number(f.notice_period_id) : null, expected_ctc: f.expected_ctc || null,
        highest_qualification: f.highest_qualification || '', university: f.university || '',
        college: f.college || '', passing_year: f.passing_year || null, percentage_cgpa: f.percentage_cgpa || '',
        linkedin: f.linkedin || '', github: f.github || '', portfolio: f.portfolio || '',
        personal_website: f.personal_website || '', professional_summary: f.professional_summary || '',
        skills: csvToArr(f.skills || ''), languages: csvToArr(f.languages || ''),
        educations: educations.filter((e2) => (e2.degree_name || e2.institution_name)),
        projects: projects.filter((p2) => p2.project_name),
        references: references.filter((r2) => r2.name),
      };
      if (!f.fresher) {
        payload.total_experience = f.total_experience || null;
        payload.current_company = f.current_company || '';
        payload.previous_company = f.previous_company || '';
        payload.current_role = f.current_role || '';
        payload.current_ctc = f.current_ctc || null;
        payload.experiences = experiences.filter((x) => x.company_name);
      }
      await api.patch('/candidates/me/', payload);
      if (resumeFile) { const fd = new FormData(); fd.append('resume', resumeFile); const r: any = await api.uploadPatch('/candidates/me/', fd); set('resume', r?.data?.resume_url ?? r?.data?.resume ?? f.resume); setResumeFile(null); }
      toast.success('Profile saved.');
    } catch (err: any) {
      const d = err?.data?.errors;
      const messages = d ? flattenErrors(d) : [];
      toast.error(messages.length ? messages.join(' ') : (err?.data?.message || 'Could not save.'));
    } finally { setSaving(false); }
  };

  if (loading) return <p className="text-slate-400 text-sm">Loading your profile…</p>;

  const resumeHref = typeof f.resume === 'string' && f.resume
    ? (f.resume.startsWith('http') ? f.resume : `${(process.env.NEXT_PUBLIC_API_URL || '').replace('/api/v1', '')}${f.resume}`)
    : null;
  const resumeName = typeof f.resume === 'string' && f.resume
    ? decodeURIComponent(f.resume.split('/').pop() || '')
    : '';
  // Uploads live under frontend/public/media, so a relative path is served
  // same-origin by Next — required for the in-page <iframe> preview (the
  // backend-host URL may refuse to render inside a frame).
  const previewSrc = typeof f.resume === 'string' && f.resume && !f.resume.startsWith('http')
    ? (f.resume.startsWith('/') ? f.resume : `/${f.resume}`)
    : resumeHref;

  const rowBox = 'border border-slate-200 dark:border-slate-800 p-4 relative';
  const delBtn = (setter: any, i: number) => (
    <button type="button" onClick={() => delRow(setter, i)} title="Remove"
      className="absolute top-2 right-2 w-6 h-6 flex items-center justify-center text-rose-500 hover:bg-rose-50 dark:hover:bg-rose-950/40"><i className="fa-solid fa-xmark" /></button>
  );
  const addBtn = (setter: any, tmpl: any, label: string) => (
    <button type="button" onClick={() => addRow(setter, tmpl)}
      className="text-xs font-bold text-[#405189] border border-[#405189]/30 px-3 py-1.5 hover:bg-[#405189]/5 transition"><i className="fa-solid fa-plus mr-1" />{label}</button>
  );

  return (
    <form onSubmit={save} className="space-y-4 w-full">
      {/* ---------- Résumé card — right below the profile summary ---------- */}
      <div className="bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-none p-5 shadow-sm">
        <div className="flex items-center justify-between gap-3 mb-3">
          <h3 className="text-sm font-bold text-[#495057] dark:text-white">
            <i className="fa-solid fa-file-lines mr-2 text-[#405189]" />Résumé
          </h3>
          {resumeHref && (
            <button type="button" onClick={() => setPreviewOpen(true)}
              className="inline-flex items-center gap-1.5 text-xs font-bold text-[#405189] border border-[#405189]/30 px-3 py-1.5 hover:bg-[#405189]/5 transition whitespace-nowrap cursor-pointer">
              <i className="fa-solid fa-eye" /> Preview Résumé
            </button>
          )}
        </div>

        <label
          onDragOver={(e) => { e.preventDefault(); if (!parsing) setDragOver(true); }}
          onDragLeave={() => setDragOver(false)}
          onDrop={(e) => { e.preventDefault(); setDragOver(false); onResumeDrop(e.dataTransfer.files?.[0] ?? null); }}
          className={`block border-2 border-dashed p-5 text-center transition ${parsing
            ? 'opacity-60 cursor-not-allowed border-slate-300 dark:border-slate-700'
            : dragOver
              ? 'cursor-pointer border-[#405189] bg-[#405189]/5'
              : 'cursor-pointer border-slate-300 dark:border-slate-700 hover:border-[#405189]/60'}`}>
          <input ref={resumeFileInputRef} type="file" accept=".pdf,.doc,.docx" className="hidden" disabled={parsing}
            onChange={(e) => {
              const file = e.target.files?.[0];
              if (file) setPendingResume(file); // preview + confirm first — upload happens on confirm
              e.target.value = ''; // allow re-selecting the same file after cancel
            }} />
          {parsing ? (
            <span className="text-sm text-slate-500">
              <i className="fa-solid fa-spinner fa-spin mr-2" />Uploading &amp; parsing résumé…
            </span>
          ) : (
            <>
              <i className="fa-solid fa-cloud-arrow-up text-xl text-[#405189] mb-1.5 block" />
              <span className="block text-sm font-semibold text-slate-700 dark:text-slate-200">
                Drag &amp; drop your résumé here, or <span className="text-[#405189] underline">upload résumé</span>
              </span>
              <span className="block text-[11px] text-slate-400 mt-1">PDF, DOC or DOCX · max 5 MB</span>
            </>
          )}
        </label>

        {(resumeName || resumeFile) && (
          <p className="text-xs text-slate-500 dark:text-slate-400 mt-2.5 flex items-center gap-1.5 min-w-0">
            {resumeFile ? (
              <>
                <i className="fa-solid fa-clock" />
                <span className="truncate">“{resumeFile.name}” will be uploaded when you save.</span>
              </>
            ) : (
              <>
                <i className="fa-solid fa-circle-check text-emerald-500" />
                <span className="shrink-0">Current résumé:</span>
                <span className="font-semibold text-slate-700 dark:text-slate-200 truncate">{resumeName}</span>
              </>
            )}
          </p>
        )}
      </div>

      {/* ---------- Résumé preview modal (in-page) ---------- */}
      {previewOpen && resumeHref && (
        <ResumePreviewModal
          url={f.resume}
          name={resumeName || 'Résumé'}
          onClose={() => setPreviewOpen(false)}
        />
      )}

      {/* ---------- Confirm the picked résumé before it is uploaded ---------- */}
      {pendingResume && (
        <ResumeUploadConfirmModal
          file={pendingResume}
          busy={parsing}
          onConfirm={async () => {
            await onResumePick(pendingResume);
            setPendingResume(null);
          }}
          onCancel={() => setPendingResume(null)}
          onChooseAnother={() => {
            setPendingResume(null);
            setTimeout(() => resumeFileInputRef.current?.click(), 50);
          }}
        />
      )}

      {/* Tabs */}
      <div className="flex flex-wrap md:flex-nowrap gap-2 border-b border-slate-200 dark:border-slate-800 pb-0 w-full">
        {TABS.map((t, i) => (
          <button key={t} type="button" onClick={() => setTab(t)}
            className={`flex-grow md:flex-1 text-center px-4 py-2 text-sm font-bold transition ${tab === t ? 'bg-[#405189] text-white' : 'bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300 hover:bg-slate-200'}`}>
            {i + 1}. {t}
          </button>
        ))}
      </div>

      <div className="bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-none p-6 shadow-sm">
        {/* ---------- Personal Info ---------- */}
        {tab === 'Personal Info' && (
          <div className="space-y-5">
            <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
              <Field label="First name" value={f.first_name} onChange={(v) => set('first_name', v)} required={true} error={fieldErrors.has('first_name')} />
              <Field label="Last name" value={f.last_name} onChange={(v) => set('last_name', v)} required={true} error={fieldErrors.has('last_name')} />
              <Field label="Email" value={f.email} readOnly required={true} />
              <PhoneField label="Phone" value={f.phone_number} onChange={(v) => set('phone_number', v)} required={true} error={fieldErrors.has('phone_number')} />
              <PhoneField label="Alternate phone" value={f.alternate_phone_number} onChange={(v) => set('alternate_phone_number', v)} error={fieldErrors.has('alternate_phone_number')} />
              <Field label="Date of birth" type="date" value={f.date_of_birth} onChange={(v) => set('date_of_birth', v)} />
              <div>
                <label className="block text-[11px] font-bold uppercase tracking-wide text-slate-500 mb-1">Gender <span className="text-red-500 font-bold">*</span></label>
                <select value={f.gender || ''} onChange={(e) => set('gender', e.target.value)} className={inputCls}>
                  <option value="">Select gender</option><option>Male</option><option>Female</option><option>Other</option>
                </select>
              </div>
            </div>
            <div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
              <div>
                <label className="block text-[11px] font-bold uppercase tracking-wide text-slate-500 mb-1">Country <span className="text-red-500 font-bold">*</span></label>
                <LocationAsyncSelect
                  locationType="country"
                  value={f.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);
                    set('country', cname);
                    set('state', '');
                    set('city', '');
                  }}
                />
                {fieldErrors.has('country') && <p className="text-[11px] font-semibold text-red-500 mt-1">This field is required.</p>}
              </div>
              <div>
                <label className="block text-[11px] font-bold uppercase tracking-wide text-slate-500 mb-1">State <span className="text-red-500 font-bold">*</span></label>
                <LocationAsyncSelect
                  locationType="state"
                  countryId={countryId}
                  value={f.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);
                    set('state', sname);
                    set('city', '');
                  }}
                />
                {fieldErrors.has('state') && <p className="text-[11px] font-semibold text-red-500 mt-1">This field is required.</p>}
              </div>
              <div>
                <label className="block text-[11px] font-bold uppercase tracking-wide text-slate-500 mb-1">City <span className="text-red-500 font-bold">*</span></label>
                <LocationAsyncSelect
                  locationType="city"
                  countryId={countryId}
                  stateId={stateId}
                  value={f.city || ''}
                  onChange={(val, option) => {
                    const opt = Array.isArray(option) ? option[0] : option;
                    const cname = opt?.name || (typeof val === 'string' ? val : '');
                    set('city', cname);
                  }}
                />
                {fieldErrors.has('city') && <p className="text-[11px] font-semibold text-red-500 mt-1">This field is required.</p>}
              </div>
            </div>
            <div>
              <label className="block text-[11px] font-bold uppercase tracking-wide text-slate-500 mb-1">Preferred locations (cities)</label>
              <LocationAsyncSelect
                locationType="city"
                allowAny
                isMulti
                value={csvToArr(f.preferred_location || '')}
                onChange={(vals: any) => {
                  const arr = (vals || []).map((v: any) => (typeof v === 'object' ? v.value : v));
                  set('preferred_location', arrToCsv(arr));
                }}
                placeholder="Search preferred cities…"
              />
            </div>
            <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
              <Field label="Current address" value={f.current_address} onChange={(v) => set('current_address', v)} required={true} />
              <Field label="Permanent address" value={f.permanent_address} onChange={(v) => set('permanent_address', v)} required={true} />
            </div>
          </div>
        )}

        {/* ---------- Education & Skills ---------- */}
        {tab === 'Education & Skills' && (
          <div className="space-y-5">
            <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
              <div>
                <label className="block text-[11px] font-bold uppercase tracking-wide text-slate-500 mb-1">Highest qualification <span className="text-red-500 font-bold">*</span></label>
                <div className={fieldErrors.has('highest_qualification') ? 'ring-1 ring-red-500' : ''}>
                  <SearchableSelect isCreatable options={eduOpts} value={f.highest_qualification || ''}
                    onChange={(v: any) => set('highest_qualification', typeof v === 'object' && v ? v.value : (v ?? ''))}
                    placeholder="Select or type…" controlBgClass="bg-white dark:bg-slate-900" />
                </div>
                {fieldErrors.has('highest_qualification') && <p className="text-[11px] font-semibold text-red-500 mt-1">This field is required.</p>}
              </div>
              <Field label="University" value={f.university} onChange={(v) => set('university', v)} />
              <Field label="College" value={f.college} onChange={(v) => set('college', v)} />
              <Field label="Passing year" type="number" value={f.passing_year} onChange={(v) => set('passing_year', v)} />
              <Field label="Percentage / CGPA" type="number" value={f.percentage_cgpa} onChange={(v) => set('percentage_cgpa', v)} />
            </div>

            <div>
              <div className="flex items-center justify-between mb-2">
                <h4 className="text-xs font-black uppercase tracking-wide text-slate-500">Education history</h4>
                {addBtn(setEducations, { degree_name: '', institution_name: '', passing_year: '', percentage_cgpa: '' }, 'Add education')}
              </div>
              <div className="space-y-3">
                {educations.map((e2, i) => (
                  <div key={i} className={rowBox}>
                    {delBtn(setEducations, i)}
                    <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
                      <Field label="Degree" value={e2.degree_name} onChange={(v) => updRow(setEducations, i, 'degree_name', v)} />
                      <Field label="Institution" value={e2.institution_name} onChange={(v) => updRow(setEducations, i, 'institution_name', v)} />
                      <Field label="Passing year" type="number" value={e2.passing_year} onChange={(v) => updRow(setEducations, i, 'passing_year', v)} />
                      <Field label="Percentage / CGPA" type="number" value={e2.percentage_cgpa} onChange={(v) => updRow(setEducations, i, 'percentage_cgpa', v)} />
                    </div>
                  </div>
                ))}
              </div>
            </div>

            <div>
              <label className="block text-[11px] font-bold uppercase tracking-wide text-slate-500 mb-1">Key skills</label>
              <SearchableSelect isMulti options={skillOpts} value={csvToArr(f.skills || '')}
                onChange={(vals: any) => set('skills', arrToCsv((vals || []).map((v: any) => (typeof v === 'object' ? v.value : v))))}
                placeholder="Select skills…" controlBgClass="bg-white dark:bg-slate-900" />
            </div>
            <div>
              <label className="block text-[11px] font-bold uppercase tracking-wide text-slate-500 mb-1">Languages</label>
              <SearchableSelect isMulti options={langOpts} value={csvToArr(f.languages || '')}
                onChange={(vals: any) => set('languages', arrToCsv((vals || []).map((v: any) => (typeof v === 'object' ? v.value : v))))}
                placeholder="Select languages…" controlBgClass="bg-white dark:bg-slate-900" />
            </div>
            <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
              <Field label="LinkedIn" value={f.linkedin} onChange={(v) => set('linkedin', v)} />
              <Field label="GitHub" value={f.github} onChange={(v) => set('github', v)} />
              <Field label="Portfolio" value={f.portfolio} onChange={(v) => set('portfolio', v)} />
              <Field label="Personal website" value={f.personal_website} onChange={(v) => set('personal_website', v)} />
            </div>
          </div>
        )}

        {/* ---------- Work Experience ---------- */}
        {tab === 'Work Experience' && (
          <div className="space-y-5">
            <label className="flex items-center gap-2 text-sm font-semibold text-slate-700 dark:text-slate-200 cursor-pointer">
              <input type="checkbox" checked={!!f.fresher} onChange={(e) => set('fresher', e.target.checked)} className="w-4 h-4 accent-[#405189]" />
              I am a fresher (no work experience)
            </label>
            <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
              <div>
                <label className="block text-[11px] font-bold uppercase tracking-wide text-slate-500 mb-1">Desired pay (annual) <span className="text-red-500 font-bold">*</span></label>
                <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)); }}
                    style={fieldErrors.has('expected_ctc') ? errStyle : undefined}
                    className={`${inputCls} ${fieldErrors.has('expected_ctc') ? errRing : ''}`}>
                    <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)); }}
                    style={fieldErrors.has('expected_ctc') ? errStyle : undefined}
                    className={`${inputCls} ${fieldErrors.has('expected_ctc') ? errRing : ''}`}>
                    <option value="">Thousands</option>
                    {THOUSANDS_OPTIONS.map((n) => <option key={n} value={n}>{n} Thousand{n === '1' ? '' : 's'}</option>)}
                  </select>
                </div>
                {fieldErrors.has('expected_ctc') && <p className="text-[11px] font-semibold text-red-500 mt-1">This field is required.</p>}
              </div>
              <SelectField label="Notice period" value={f.notice_period_id} onChange={(v) => set('notice_period_id', v)} options={noticeOpts} required={true} placeholder="Select notice period" />
            </div>
            {!f.fresher && (
              <>
                <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
                  <ExperienceField value={f.total_experience} onChange={(v) => set('total_experience', v)} required={true} />
                  <Field label="Current employer" value={f.current_company} onChange={(v) => set('current_company', v)} required={true} />
                  <div>
                    <label className="block text-[11px] font-bold uppercase tracking-wide text-slate-500 mb-1">Designation <span className="text-red-500 font-bold">*</span></label>
                    <SearchableSelect options={desigOpts} value={f.current_role || ''}
                      onChange={(v: any) => set('current_role', typeof v === 'object' && v ? v.value : (v ?? ''))}
                      placeholder="Select designation…" controlBgClass="bg-white dark:bg-slate-900" />
                  </div>
                  <div>
                    <label className="block text-[11px] font-bold uppercase tracking-wide text-slate-500 mb-1">Annual salary (current) <span className="text-red-500 font-bold">*</span></label>
                    <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)); }}
                        style={fieldErrors.has('current_ctc') ? errStyle : undefined}
                        className={`${inputCls} ${fieldErrors.has('current_ctc') ? errRing : ''}`}>
                        <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)); }}
                        style={fieldErrors.has('current_ctc') ? errStyle : undefined}
                        className={`${inputCls} ${fieldErrors.has('current_ctc') ? errRing : ''}`}>
                        <option value="">Thousands</option>
                        {THOUSANDS_OPTIONS.map((n) => <option key={n} value={n}>{n} Thousand{n === '1' ? '' : 's'}</option>)}
                      </select>
                    </div>
                    {fieldErrors.has('current_ctc') && <p className="text-[11px] font-semibold text-red-500 mt-1">This field is required.</p>}
                  </div>
                </div>
                <div>
                  <div className="flex items-center justify-between mb-2">
                    <h4 className="text-xs font-black uppercase tracking-wide text-slate-500">Past experience</h4>
                    {addBtn(setExperiences, { company_name: '', role: '', joining_date: '', last_working_date: '' }, 'Add experience')}
                  </div>
                  <div className="space-y-3">
                    {experiences.map((x, i) => (
                      <div key={i} className={rowBox}>
                        {delBtn(setExperiences, i)}
                        <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
                          <Field label="Company" value={x.company_name} onChange={(v) => updRow(setExperiences, i, 'company_name', v)} />
                          <Field label="Role" value={x.role} onChange={(v) => updRow(setExperiences, i, 'role', v)} />
                          <Field label="From" type="date" value={x.joining_date} onChange={(v) => updRow(setExperiences, i, 'joining_date', v)} />
                          <Field label="To" type="date" value={x.last_working_date} onChange={(v) => updRow(setExperiences, i, 'last_working_date', v)} />
                        </div>
                      </div>
                    ))}
                  </div>
                </div>
              </>
            )}
          </div>
        )}

        {/* ---------- Projects ---------- */}
        {tab === 'Projects' && (
          <div className="space-y-3">
            <div className="flex items-center justify-between">
              <h4 className="text-xs font-black uppercase tracking-wide text-slate-500">Projects</h4>
              {addBtn(setProjects, { project_name: '', description: '', technologies_used: '', role: '', duration: '' }, 'Add project')}
            </div>
            {projects.length === 0 && <p className="text-sm text-slate-400">No projects added.</p>}
            {projects.map((p2, i) => (
              <div key={i} className={rowBox}>
                {delBtn(setProjects, i)}
                <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
                  <Field label="Project name" value={p2.project_name} onChange={(v) => updRow(setProjects, i, 'project_name', v)} />
                  <Field label="Role" value={p2.role} onChange={(v) => updRow(setProjects, i, 'role', v)} />
                  <div>
                    <label className="block text-[11px] font-bold uppercase tracking-wide text-slate-500 mb-1">Technologies used</label>
                    <SearchableSelect isMulti options={skillOpts}
                      value={csvToArr(p2.technologies_used || '')}
                      onChange={(vals: any) => updRow(setProjects, i, 'technologies_used', arrToCsv((vals || []).map((v: any) => (typeof v === 'object' ? v.value : v))))}
                      placeholder="Select technologies…" controlBgClass="bg-white dark:bg-slate-900" />
                  </div>
                  <Field label="Duration" value={p2.duration} onChange={(v) => updRow(setProjects, i, 'duration', v)} />
                </div>
                <div className="mt-3">
                  <label className="block text-[11px] font-bold uppercase tracking-wide text-slate-500 mb-1">Description</label>
                  <textarea rows={2} value={p2.description || ''} onChange={(e) => updRow(setProjects, i, 'description', e.target.value)} className={inputCls} />
                </div>
              </div>
            ))}
          </div>
        )}

        {/* ---------- References ---------- */}
        {tab === 'References' && (
          <div className="space-y-3">
            <div className="flex items-center justify-between">
              <h4 className="text-xs font-black uppercase tracking-wide text-slate-500">References</h4>
              {addBtn(setReferences, { name: '', designation: '', company: '', email: '', phone: '', relationship: '' }, 'Add reference')}
            </div>
            {references.length === 0 && <p className="text-sm text-slate-400">No references added.</p>}
            {references.map((r2, i) => (
              <div key={i} className={rowBox}>
                {delBtn(setReferences, i)}
                <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
                  <Field label="Name" value={r2.name} onChange={(v) => updRow(setReferences, i, 'name', v)} />
                  <Field label="Designation" value={r2.designation} onChange={(v) => updRow(setReferences, i, 'designation', v)} />
                  <Field label="Company" value={r2.company} onChange={(v) => updRow(setReferences, i, 'company', v)} />
                  <Field label="Relationship" value={r2.relationship} onChange={(v) => updRow(setReferences, i, 'relationship', v)} />
                  <Field label="Email" value={r2.email} onChange={(v) => updRow(setReferences, i, 'email', v)} />
                  <Field label="Phone" value={r2.phone} onChange={(v) => updRow(setReferences, i, 'phone', v)} />
                </div>
              </div>
            ))}
          </div>
        )}
      </div>

      {/* Persistent: summary + save */}
      <div className="bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-none p-6 shadow-sm space-y-4">
        <div>
          <label className="block text-[11px] font-bold uppercase tracking-wide text-slate-500 mb-1">Professional summary</label>
          <textarea rows={3} value={f.professional_summary || ''} onChange={(e) => set('professional_summary', e.target.value)} className={inputCls} />
        </div>
        <div className="flex justify-end">
          <button type="submit" disabled={saving} className="px-8 py-2.5 bg-[#405189] text-white font-bold text-sm hover:bg-[#334267] transition disabled:opacity-50">
            {saving ? 'Saving…' : 'Save profile'}
          </button>
        </div>
      </div>
    </form>
  );
}
