/* ---------- Add employee ---------- */
function fmtJoined(iso) {
  if (!iso) return "—";
  var d = new Date(iso + "T00:00:00");
  return isNaN(d) ? iso : d.toLocaleString(uiLocale(), { month: "short", year: "numeric" });
}

/* Departments and job titles are the same thing twice: a name-only pick-list
   the employee record stores as text, get-or-created by name on the server and
   renamed with the employees following along. One modal serves both — `labels`
   is which set of strings to wear. */
const DEPT_LABELS = {
  add: "hr.addDepartment", edit: "hr.editDepartment",
  createSub: "hr.createDeptSub", renameSub: "hr.renameDeptSub",
  nameLabel: "hr.departmentName", placeholder: "hr.deptPlaceholder",
  errRequired: "hr.errDeptName", errExists: "hr.errDeptExists"
};
const TITLE_LABELS = {
  add: "hr.addJobTitle", edit: "hr.editJobTitle",
  createSub: "hr.createTitleSub", renameSub: "hr.renameTitleSub",
  nameLabel: "hr.jobTitle", placeholder: "hr.jobTitlePlaceholder",
  errRequired: "hr.errJobTitle", errExists: "hr.errTitleExists"
};

function PickListModal({ open, initial, existing, labels, onClose, onSave }) {
  const { useState, useEffect } = React;
  const [name, setName] = useState("");
  const [err, setErr] = useState("");
  const [busy, setBusy] = useState(false);
  const editing = !!(initial && initial.oldName);
  const L = labels || DEPT_LABELS;

  useEffect(() => {
    if (open) { setName(initial ? initial.name : ""); setErr(""); setBusy(false); }
  }, [open, initial]);

  const save = () => {
    const n = name.trim();
    if (!n) { setErr(T(L.errRequired)); return; }
    const clash = existing.some((d) => d.toLowerCase() === n.toLowerCase() && (!editing || d !== initial.oldName));
    if (clash) { setErr(T(L.errExists)); return; }
    setBusy(true);
    Promise.resolve(onSave(n)).catch(() => setBusy(false));
  };

  return (
    <Modal open={open} onClose={onClose} width={400} z={160}
      title={editing ? T(L.edit) : T(L.add)}
      sub={editing ? T(L.renameSub, { name: initial.oldName }) : T(L.createSub)}
      footer={
        <div className="btnrow">
          <Btn onClick={onClose}>{T("common.cancel")}</Btn>
          <Btn variant="primary" icon={editing ? "check" : "plus"} onClick={save} disabled={busy}>
            {editing ? T("common.saveChanges") : T(L.add)}
          </Btn>
        </div>
      }>
      <Field label={T(L.nameLabel)} error={err}>
        <Input placeholder={T(L.placeholder)} value={name} autoFocus
          onChange={(e) => setName(e.target.value)}
          onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); save(); } }} />
      </Field>
    </Modal>
  );
}

/* A rejected portal login belongs on the box that caused it, not in a toast the
   admin reads after the popup is gone. The server tags each 400 with a code; the
   ones worth phrasing in both languages get our own wording, the rest fall back
   to the server's own text. */
const ACCOUNT_ERRS = {
  username_taken: { on: "username", key: "hr.errUsernameTaken" },
  username_invalid: { on: "username", key: "hr.errUsernameChars" },
  identifier_required: { on: "username", key: "hr.errPortalUsername" },
  email_taken: { on: "email", key: "hr.errEmailTaken" },
  email_invalid: { on: "email", key: "hr.errValidEmail" },
  password_weak: { on: "pw", key: null }, // Django's own wording is the specific one
  account_exists: { on: "form", key: "hr.errAccountExists" }
};

/* Thrown API error -> {username|email|pw|form: message} for the error state. */
function serverErrs(ex) {
  const data = (ex && ex.data) || null;
  const text = (data && data.error) || "";
  const hit = data && ACCOUNT_ERRS[data.code];
  if (hit) return { [hit.on]: hit.key ? T(hit.key) : text };
  return { form: text || T("hr.errSaveFailed") };
}

function AddEmployeeModal({ open, existing, onClose, onAdd, initial, onPickListRenamed }) {
  const { useState, useEffect } = React;
  const [form, setForm] = useState({ name: "", role: "", dept: "", salary: "", joined: "", status: "Active", username: "", email: "", pw: "" });
  const [errs, setErrs] = useState({});
  const [saving, setSaving] = useState(false);
  const [deptList, setDeptList] = useState([]); // [{id|null, name}]
  const [deptModal, setDeptModal] = useState(null); // {id|null, name, oldName|null}
  const [titleList, setTitleList] = useState([]); // [{id|null, name}]
  const [titleModal, setTitleModal] = useState(null); // {id|null, name, oldName|null}
  useEffect(() => {
    if (open) {
      setForm(initial
        ? { name: initial.name, role: initial.role, dept: initial.dept, salary: String(initial.salary), joined: "", status: initial.status, username: "", email: "", pw: "" }
        : { name: "", role: "", dept: "", salary: "", joined: "", status: "Active", username: "", email: "", pw: "" });
      setErrs({});
      setSaving(false);
      API.departments.list().then(setDeptList).catch(() => setDeptList([]));
      API.jobTitles.list().then(setTitleList).catch(() => setTitleList([]));
    }
  }, [open, initial]);

  const depts = deptList.map((d) => d.name);
  const titles = titleList.map((t) => t.name);
  const set = (patch) => setForm((f) => ({ ...f, ...patch }));
  const signInLink = API.signInLink(); // null until a company link pinned the tenant

  const saveDept = async (name) => {
    const m = deptModal;
    if (m && m.oldName) { // rename
      try {
        const d = await API.departments.rename(m.id, name);
        setDeptList((ds) => ds.map((x) => (x.id === d.id ? d : x)));
      } catch (ex) { notify(T("hr.errRenameDept", { message: ex.message })); return; }
      if (form.dept === m.oldName) set({ dept: name });
      if (onPickListRenamed) onPickListRenamed();
      notify(T("hr.deptRenamedTo", { name: name }));
    } else { // create
      try {
        const d = await API.departments.create(name);
        setDeptList((ds) => (ds.some((x) => x.id === d.id) ? ds : [...ds, d]));
      } catch (ex) { notify(T("hr.errAddDept", { message: ex.message })); return; }
      set({ dept: name });
      notify(T("hr.deptAdded", { name: name }));
    }
    setDeptModal(null);
  };

  const saveTitle = async (name) => {
    const m = titleModal;
    if (m && m.oldName) { // rename
      try {
        const t = await API.jobTitles.rename(m.id, name);
        setTitleList((ts) => ts.map((x) => (x.id === t.id ? t : x)));
      } catch (ex) { notify(T("hr.errRenameTitle", { message: ex.message })); return; }
      if (form.role === m.oldName) set({ role: name });
      if (onPickListRenamed) onPickListRenamed();
      notify(T("hr.titleRenamedTo", { name: name }));
    } else { // create
      try {
        const t = await API.jobTitles.create(name);
        setTitleList((ts) => (ts.some((x) => x.id === t.id) ? ts : [...ts, t]));
      } catch (ex) { notify(T("hr.errAddTitle", { message: ex.message })); return; }
      set({ role: name });
      notify(T("hr.titleAdded", { name: name }));
    }
    setTitleModal(null);
  };

  const save = async () => {
    const e = {};
    // Sign-in ignores case, so the account is always created lowercase.
    const user = form.username.trim().toLowerCase();
    const mail = form.email.trim().toLowerCase();
    // Filling in any credential field asks for a portal account. A username is
    // enough on its own — employees usually have no email to sign in with.
    const wantsAccount = !!(user || mail || form.pw);
    // The name is the only thing hiring can't happen without. A job title and a
    // department are often settled after the fact, so both go in empty and get
    // filled from the profile later.
    if (!form.name.trim()) e.name = T("hr.errEmployeeName");
    if (wantsAccount && !user && !mail) e.username = T("hr.errPortalUsername");
    if (user && !/^[\w.@+-]+$/.test(user)) e.username = T("hr.errUsernameChars");
    if (mail && mail.indexOf("@") < 0) e.email = T("hr.errValidEmail");
    if (wantsAccount && !form.pw) e.pw = T("hr.errPortalPassword");
    setErrs(e);
    if (Object.keys(e).length) return;
    const rec = { name: form.name.trim(), role: form.role.trim(), dept: form.dept.trim(),
      joined: form.joined ? fmtJoined(form.joined) : (initial ? initial.joined : fmtJoined("")),
      joinedIso: form.joined || null, status: form.status,
      accountUsername: user || null,
      accountEmail: mail || null, accountPassword: form.pw || null };
    // Salary and start date are never set here — both belong to the contract, which is
    // opened from the profile after hiring. Sending no salary means no contract is created.
    setSaving(true);
    try {
      // onAdd closes the modal itself once everything landed. A rejected username
      // or email rejects instead, and the popup stays open on a filled-in form so
      // the admin can fix that one box and save again.
      await Promise.resolve(onAdd(rec));
    } catch (ex) {
      setErrs(serverErrs(ex));
    } finally {
      setSaving(false);
    }
  };

  return (
    <Modal open={open} onClose={onClose} width={520}
      title={initial ? T("hr.editEmployee") : T("hr.addEmployee")}
      sub={initial ? T("hr.updateRecordSub", { name: initial.name }) : T("hr.newTeamMemberSub")}
      footer={
        <div className="btnrow">
          <Btn onClick={onClose}>{T("common.cancel")}</Btn>
          <Btn variant="primary" icon={initial ? "check" : "plus"} onClick={save} disabled={saving}>
            {initial ? T("common.saveChanges") : T("hr.addEmployee")}
          </Btn>
        </div>
      }>
      {/* Rejections with no field of their own (a dead server, an employee who
          already has a login) sit at the top rather than vanishing into a toast. */}
      {errs.form ? <div className="form-err"><Icon name="alert" size={14} />{errs.form}</div> : null}
      <Field label={T("common.fullName")} error={errs.name}>
        <Input placeholder={T("common.fullName")} value={form.name} autoFocus onChange={(e) => set({ name: e.target.value })} />
      </Field>
      <Field label={T("hr.jobTitleOptional")} error={errs.role}>
        <SearchSelect options={titles} placeholder={T("hr.chooseOrAdd")} value={form.role}
          onChange={(v) => set({ role: v })} addLabel={T("hr.addJobTitle")}
          onAdd={(q) => setTitleModal({ id: null, name: q || "", oldName: null })}
          onEditRow={(name) => {
            const t = titleList.find((x) => x.name === name);
            setTitleModal({ id: t ? t.id : null, name: name, oldName: name });
          }} />
      </Field>
      <div className="formgrid">
        <Field label={T("hr.departmentOptional")} error={errs.dept}>
          <SearchSelect options={depts} placeholder={T("hr.chooseOrAdd")} value={form.dept}
            onChange={(v) => set({ dept: v })} addLabel={T("hr.addDepartment")}
            onAdd={(q) => setDeptModal({ id: null, name: q || "", oldName: null })}
            onEditRow={(name) => {
              const d = deptList.find((x) => x.name === name);
              setDeptModal({ id: d ? d.id : null, name: name, oldName: name });
            }} />
        </Field>
        <Field label={T("common.status")}>
          <SearchSelect options={["Active", "On leave", "Probation"]} value={form.status} onChange={(v) => set({ status: v })} />
        </Field>
      </div>
      {initial ? (
        <div className="formgrid">
          <Field label={T("hr.salaryPerMonth")}>
            <Input type="number" min="0" step="100" placeholder="0" value={form.salary} disabled
              title={T("hr.salarySetByContract")} />
            <span className="formhint" style={{ display: "block" }}>{T("hr.salaryContractHint")}</span>
          </Field>
          <Field label={T("hr.joinedKeepHint", { date: initial.joined })}>
            <Input type="date" value={form.joined} onChange={(e) => set({ joined: e.target.value })} />
          </Field>
        </div>
      ) : null}
      {!initial ? (
        <div className="role-locked" style={{ margin: "2px 0 12px" }}>
          <Icon name="alert" size={14} />{T("hr.noContractOnHire")}
        </div>
      ) : null}
      {!initial ? (
        <React.Fragment>
          <div className="formgrid">
            <Field label={T("hr.portalUsername")} error={errs.username}>
              <Input placeholder={T("hr.usernamePlaceholder")} value={form.username}
                onChange={(e) => set({ username: e.target.value.toLowerCase() })} />
            </Field>
            <Field label={T("hr.portalEmailOptional")} error={errs.email}>
              <Input type="email" placeholder="name@company.com" value={form.email} onChange={(e) => set({ email: e.target.value.toLowerCase() })} />
            </Field>
          </div>
          <Field label={T("hr.portalPassword")} error={errs.pw}>
            <Input type="password" placeholder="••••••••" value={form.pw} onChange={(e) => set({ pw: e.target.value })} />
            {/* A username is only checkable on the company's own backend, so staff
                need the ?d= link — show the admin exactly which link to send. */}
            <span className="formhint" style={{ display: "block" }}>
              {signInLink ? T("hr.portalCredsLink", { link: signInLink }) : T("hr.portalCredsHint")}
            </span>
          </Field>
        </React.Fragment>
      ) : null}
      <PickListModal open={!!deptModal} initial={deptModal} existing={depts} labels={DEPT_LABELS}
        onClose={() => setDeptModal(null)} onSave={saveDept} />
      <PickListModal open={!!titleModal} initial={titleModal} existing={titles} labels={TITLE_LABELS}
        onClose={() => setTitleModal(null)} onSave={saveTitle} />
    </Modal>
  );
}

window.AddEmployeeModal = AddEmployeeModal;
window.fmtJoined = fmtJoined;
