/* ════════════════════════════════════════════════════════════════════════
   MSINDAHA Operations — SHARED WORK-ITEM COMPONENTS
   Used by both tickets and tasks: people/assignment pickers, property
   menus (status / priority / category), the activity timeline with
   comments, the comment composer, and multi-assignee progress.
════════════════════════════════════════════════════════════════════════ */

const URL_RE = /(https?:\/\/[^\s<]+[^\s<.,;:!?)\]'"])/g;
// Plain text with clickable links and preserved line breaks.
function RichText({ text }) {
  const parts = String(text || "").split(URL_RE);
  return parts.map((p, i) =>
    i % 2 === 1 ? (
      <a key={i} href={p} target="_blank" rel="noopener noreferrer" onClick={(e) => e.stopPropagation()}>
        {p}
      </a>
    ) : (
      <React.Fragment key={i}>{p}</React.Fragment>
    ),
  );
}

// People this user may assign: active accounts, own department unless
// Super Admin (who works across departments).
function assignableUsers(users, role) {
  return activeUsersOf(users)
    .filter((u) => role === "super-admin" || (u.department || "payroll") === MY_DEPARTMENT || u.role === "super-admin")
    .sort((a, b) => userLabel(a).localeCompare(userLabel(b)));
}

/* PeopleList — searchable list of people, single or multi select. */
function PeopleList({ people, selected, onToggle, multiple, meUid, allowNone, maxHeight = 232, autoFocus }) {
  const [q, setQ] = React.useState("");
  const filtered = people.filter((u) => {
    if (!q.trim()) return true;
    const s = q.trim().toLowerCase();
    return `${userLabel(u)} ${u.email || ""}`.toLowerCase().includes(s);
  });
  return (
    <div className="people-list">
      <div className="people-search">
        <IC.Search />
        <input
          value={q}
          onChange={(e) => setQ(e.target.value)}
          placeholder="Search people…"
          autoFocus={autoFocus}
          data-autofocus={autoFocus ? "" : undefined}
        />
      </div>
      <div className="people-items" style={{ maxHeight }}>
        {allowNone && !multiple && !q && (
          <button
            type="button"
            className={cx("people-item", selected.length === 0 && "selected")}
            onClick={() => onToggle(null)}
          >
            <span className="avatar-ph" style={{ width: 26, height: 26 }} />
            <span className="people-name">Unassigned</span>
            {selected.length === 0 && <IC.Check />}
          </button>
        )}
        {filtered.length === 0 && <div className="people-empty">No one matches "{q}".</div>}
        {filtered.map((u) => {
          const on = selected.includes(u._id);
          return (
            <button
              type="button"
              key={u._id}
              className={cx("people-item", on && "selected")}
              onClick={() => onToggle(u._id)}
            >
              {multiple && (
                <span className={cx("checkbox", on && "on")}>{on && <IC.Check />}</span>
              )}
              <Avatar name={userLabel(u)} email={u.email} size={26} />
              <span className="people-name">
                {userLabel(u)}
                {u._id === meUid && <span className="you-tag">you</span>}
              </span>
              <span className="people-meta">
                {u.role === "super-admin" ? "Super Admin" : deptLabelOf(u.department || "payroll")}
              </span>
              {!multiple && on && <IC.Check />}
            </button>
          );
        })}
      </div>
    </div>
  );
}

/* AssignmentPicker — mode switch + matching target picker. Employees only
   get "One person" (rules: they can't create team-wide assignments);
   multi-department / company are Super Admin only. */
function AssignmentPicker({ value, onChange, users, role, meUid, canAssignBeyondSelf = true }) {
  const isSuper = role === "super-admin";
  const a = value || blankAssignment();
  const people = assignableUsers(users, role);
  const modes = [
    { value: "individual", label: "One person" },
    ...(canAssignBeyondSelf
      ? [
          { value: "multiple", label: "Several people" },
          { value: "department", label: "Department" },
        ]
      : []),
    ...(isSuper && canAssignBeyondSelf
      ? [
          { value: "multi-department", label: "Departments" },
          { value: "company", label: "Company" },
        ]
      : []),
  ];
  const setMode = (mode) => {
    if (mode === a.mode) return;
    if (mode === "department") onChange({ mode, uids: [], departments: [MY_DEPARTMENT] });
    else if (mode === "company") onChange({ mode, uids: [], departments: DEPARTMENTS.map((d) => d.id) });
    else if (mode === "multiple") onChange({ mode, uids: a.mode === "individual" ? a.uids : [], departments: [] });
    else if (mode === "individual") onChange({ mode, uids: a.mode === "multiple" ? a.uids.slice(0, 1) : [], departments: [] });
    else onChange({ mode, uids: [], departments: [] });
  };
  const toggleDept = (id) => {
    const departments = a.departments.includes(id) ? a.departments.filter((d) => d !== id) : [...a.departments, id];
    onChange({ ...a, departments });
  };
  const selectedPeople = resolveAssignees(a, users);

  return (
    <div className="assign-picker">
      {modes.length > 1 && <Segmented size="sm" value={a.mode} onChange={setMode} options={modes} className="assign-modes" />}

      {a.mode === "individual" && (
        <PeopleList
          people={people}
          selected={a.uids}
          meUid={meUid}
          allowNone
          onToggle={(uid) => onChange({ ...a, uids: uid ? [uid] : [] })}
        />
      )}

      {a.mode === "multiple" && (
        <>
          {selectedPeople.length > 0 && (
            <div className="chip-row">
              {selectedPeople.map((p) => (
                <span key={p.uid} className="person-chip">
                  <Avatar name={p.name} email={p.email} size={18} />
                  {p.name}
                  <button
                    type="button"
                    aria-label={`Remove ${p.name}`}
                    onClick={() => onChange({ ...a, uids: a.uids.filter((x) => x !== p.uid) })}
                  >
                    <IC.X />
                  </button>
                </span>
              ))}
            </div>
          )}
          <PeopleList
            people={people}
            selected={a.uids}
            meUid={meUid}
            multiple
            onToggle={(uid) =>
              onChange({ ...a, uids: a.uids.includes(uid) ? a.uids.filter((x) => x !== uid) : [...a.uids, uid] })
            }
          />
          <div className="form-hint">Each person tracks their own part; you can see everyone's progress.</div>
        </>
      )}

      {a.mode === "department" &&
        (isSuper ? (
          <div className="option-list">
            {DEPARTMENTS.map((d) => (
              <button
                type="button"
                key={d.id}
                className={cx("option-row", a.departments[0] === d.id && "selected")}
                onClick={() => onChange({ ...a, departments: [d.id] })}
              >
                <span className={cx("radio", a.departments[0] === d.id && "on")} />
                {d.label}
              </button>
            ))}
          </div>
        ) : (
          <div className="assign-note">
            <IC.Layers />
            <span>
              Everyone in <strong>{deptLabelOf(MY_DEPARTMENT)}</strong> sees it. The first person to finish it completes it for
              the whole team.
            </span>
          </div>
        ))}

      {a.mode === "multi-department" && (
        <div className="option-list">
          {DEPARTMENTS.map((d) => {
            const on = a.departments.includes(d.id);
            return (
              <button type="button" key={d.id} className={cx("option-row", on && "selected")} onClick={() => toggleDept(d.id)}>
                <span className={cx("checkbox", on && "on")}>{on && <IC.Check />}</span>
                {d.label}
              </button>
            );
          })}
        </div>
      )}

      {a.mode === "company" && (
        <div className="assign-note">
          <IC.Globe />
          <span>Visible to everyone, in every department. The first person to finish it completes it for all.</span>
        </div>
      )}
    </div>
  );
}
// Validation shared by the create/edit forms.
const assignmentError = (a) => {
  if (!a) return null;
  if (a.mode === "multiple" && a.uids.length < 2) return "Pick at least two people, or switch to “One person”.";
  if (a.mode === "multi-department" && a.departments.length < 1) return "Pick at least one department.";
  return null;
};

/* AssigneeMenu — quick reassignment from the detail drawer (editors). */
function AssigneeMenu({ item, users, role, meUid, onChange, onAdvanced, disabled }) {
  const a = assignmentOf(item);
  const people = assignableUsers(users, role);
  if (disabled) return <AssigneeCell item={item} users={users} size={22} />;
  return (
    <Dropdown
      width={300}
      trigger={({ ref, toggle, open }) => (
        <button ref={ref} type="button" className={cx("prop-btn", open && "open")} onClick={toggle}>
          <AssigneeCell item={item} users={users} size={22} />
          <IC.ChevronDown />
        </button>
      )}
    >
      {({ close }) => (
        <div className="assignee-menu">
          <PeopleList
            people={people}
            selected={a?.mode === "individual" ? a.uids : []}
            meUid={meUid}
            allowNone
            autoFocus
            maxHeight={260}
            onToggle={(uid) => {
              close();
              onChange({ mode: "individual", uids: uid ? [uid] : [], departments: [] });
            }}
          />
          {onAdvanced && (
            <div className="assignee-menu-foot">
              <button
                type="button"
                className="link-btn"
                onClick={() => {
                  close();
                  onAdvanced();
                }}
              >
                <IC.Users /> Several people or a department…
              </button>
            </div>
          )}
        </div>
      )}
    </Dropdown>
  );
}

/* Property menus for the detail drawer. */
function StatusMenu({ status, kind = "ticket", allowed, onChange }) {
  const options = kind === "task" ? TASK_STATUSES : TICKET_STATUSES;
  const can = allowed && allowed.length > 0;
  if (!can) return <StatusBadge status={status} kind={kind} />;
  return (
    <Dropdown
      width={210}
      trigger={({ ref, toggle, open }) => (
        <button ref={ref} type="button" className={cx("prop-btn", open && "open")} onClick={toggle}>
          <StatusBadge status={status} kind={kind} />
          <IC.ChevronDown />
        </button>
      )}
    >
      {({ close }) => (
        <MenuList>
          {options
            .filter((s) => allowed.includes(s) || s === status)
            .map((s) => (
              <MenuItem
                key={s}
                checkable
                active={s === status}
                onSelect={() => {
                  close();
                  if (s !== status) onChange(s);
                }}
              >
                <StatusBadge status={s} kind={kind} />
              </MenuItem>
            ))}
        </MenuList>
      )}
    </Dropdown>
  );
}
function PriorityMenu({ value, onChange, disabled }) {
  if (disabled) return <PriorityTag p={value || "medium"} />;
  return (
    <Dropdown
      width={190}
      trigger={({ ref, toggle, open }) => (
        <button ref={ref} type="button" className={cx("prop-btn", open && "open")} onClick={toggle}>
          <PriorityTag p={value || "medium"} />
          <IC.ChevronDown />
        </button>
      )}
    >
      {({ close }) => (
        <MenuList>
          {PRIORITIES.map((p) => (
            <MenuItem
              key={p}
              checkable
              active={p === value}
              onSelect={() => {
                close();
                if (p !== value) onChange(p);
              }}
            >
              <PriorityTag p={p} />
            </MenuItem>
          ))}
        </MenuList>
      )}
    </Dropdown>
  );
}
function CategoryMenu({ value, options, onChange, disabled }) {
  const label = (
    <span className="cat-tag">
      <IC.Tag />
      {value || "General"}
    </span>
  );
  if (disabled) return label;
  const all = options.includes(value) || !value ? options : [...options, value];
  return (
    <Dropdown
      width={200}
      trigger={({ ref, toggle, open }) => (
        <button ref={ref} type="button" className={cx("prop-btn", open && "open")} onClick={toggle}>
          {label}
          <IC.ChevronDown />
        </button>
      )}
    >
      {({ close }) => (
        <MenuList>
          {all.map((c) => (
            <MenuItem
              key={c}
              checkable
              active={c === value}
              onSelect={() => {
                close();
                if (c !== value) onChange(c);
              }}
            >
              {c}
            </MenuItem>
          ))}
        </MenuList>
      )}
    </Dropdown>
  );
}

/* PrioritySelector — the 4 priorities as a segmented control in forms. */
function PrioritySelector({ value, onChange }) {
  return (
    <div className="prio-selector" role="radiogroup" aria-label="Priority">
      {["low", "medium", "high", "critical"].map((p) => (
        <button
          key={p}
          type="button"
          role="radio"
          aria-checked={value === p}
          className={cx("prio-option", `prio-${p}`, value === p && "active")}
          onClick={() => onChange(p)}
        >
          <PriorityIcon p={p} />
          {priorityLabel(p)}
        </button>
      ))}
    </div>
  );
}

function PropRow({ label, icon: Icon, children }) {
  return (
    <div className="prop-row">
      <div className="prop-label">
        {Icon && <Icon />}
        {label}
      </div>
      <div className="prop-value">{children}</div>
    </div>
  );
}

function CompletionLine({ completion, verb = "Completed" }) {
  if (!completion?.completedBy) return null;
  return (
    <div className="completion-line">
      <IC.CheckCircle />
      <span>
        {verb} by <strong>{completion.completedBy.name}</strong> · {fmtDateTime(completion.completedAt)}
      </span>
    </div>
  );
}

/* Per-person progress for "several people" assignments. The bar is a
   meter: green fill on a lighter green track, with the count as text. */
function AssigneeProgress({ item, users, meUid, canToggle, onToggleMine, busy }) {
  const a = assignmentOf(item);
  if (a?.mode !== "multiple") return null;
  const people = resolveAssignees(a, users);
  const isDone = (uid) => item.assigneeProgress?.[uid]?.status === "completed";
  const done = people.filter((p) => isDone(p.uid)).length;
  const pct = people.length ? Math.round((done / people.length) * 100) : 0;
  const mineDone = isDone(meUid);
  return (
    <div className="progress-card">
      <div className="progress-head">
        <span>Assignee progress</span>
        <span className="progress-count">
          {done} of {people.length} done
        </span>
      </div>
      <div className="meter" role="meter" aria-valuemin={0} aria-valuemax={people.length} aria-valuenow={done}>
        <span style={{ width: `${pct}%` }} />
      </div>
      <ul className="progress-list">
        {people.map((p) => {
          const pr = item.assigneeProgress?.[p.uid];
          return (
            <li key={p.uid}>
              <Avatar name={p.name} email={p.email} size={22} />
              <span className="progress-name">
                {p.name}
                {p.uid === meUid && <span className="you-tag">you</span>}
              </span>
              {isDone(p.uid) ? (
                <span className="progress-done" title={fmtDateTime(pr?.completedAt)}>
                  <IC.Check /> Done {pr?.completedAt ? `· ${timeAgo(pr.completedAt)}` : ""}
                </span>
              ) : (
                <span className="progress-pending">Pending</span>
              )}
            </li>
          );
        })}
      </ul>
      {canToggle && (
        <button className={cx("btn btn-sm", mineDone ? "btn-ghost" : "btn-success")} onClick={onToggleMine} disabled={busy}>
          {mineDone ? (
            <>
              <IC.Reopen /> Undo my part
            </>
          ) : (
            <>
              <IC.Check /> Mark my part done
            </>
          )}
        </button>
      )}
    </div>
  );
}

/* ─── Activity timeline: comments + recorded events, oldest first. ──── */
const EVENT_ICONS = {
  created: IC.Plus,
  status: IC.Activity,
  assign: IC.Target,
  priority: IC.Flag,
  due: IC.Calendar,
  category: IC.Tag,
  edit: IC.Edit,
  progress: IC.CheckCheck,
  resolved: IC.CheckCircle,
  completed: IC.CheckCircle,
  visibility: IC.Eye,
};
const EVENT_TONES = {
  created: "blue",
  status: "amber",
  assign: "indigo",
  priority: "orange",
  due: "teal",
  progress: "green",
  resolved: "green",
  completed: "green",
};
function ActivityTimeline({ item, kind = "ticket", filter = "all" }) {
  const entries = React.useMemo(() => {
    const list = [];
    if (item.createdAt)
      list.push({
        kind: "event",
        type: "created",
        author: item.createdBy,
        at: item.createdAt,
        text: kind === "task" ? "created this task" : "opened this ticket",
        _key: "created",
      });
    (item.comments || []).forEach((c, i) => list.push({ ...c, _key: `c${i}` }));
    return list.filter((e) => e.at).sort((a, b) => (a.at || "").localeCompare(b.at || ""));
  }, [item.comments, item.createdAt, kind]);
  const shown = entries.filter((e) =>
    filter === "all" ? true : filter === "comments" ? e.kind !== "event" : e.kind === "event",
  );
  if (!shown.length)
    return (
      <div className="timeline-empty">
        {filter === "comments" ? "No comments yet — start the conversation below." : "No activity yet."}
      </div>
    );
  return (
    <div className="timeline">
      {shown.map((e) =>
        e.kind === "event" ? (
          <div key={e._key} className="tl-event">
            <span className={cx("tl-icon", `tone-${EVENT_TONES[e.type] || "gray"}`)}>
              {React.createElement(EVENT_ICONS[e.type] || IC.Activity)}
            </span>
            <span className="tl-text">
              <b>{e.author?.name || "Someone"}</b> {e.text}
            </span>
            <span className="tl-time" title={fmtDateTime(e.at)}>
              {timeAgo(e.at)}
            </span>
          </div>
        ) : (
          <div key={e._key} className="tl-comment">
            <Avatar name={e.author?.name} email={e.author?.email} size={30} />
            <div className="tl-bubble">
              <div className="tl-meta">
                <b>{e.author?.name || "User"}</b>
                <span title={fmtDateTime(e.at)}>{timeAgo(e.at)}</span>
              </div>
              <div className="tl-body">
                <RichText text={e.text} />
              </div>
            </div>
          </div>
        ),
      )}
    </div>
  );
}

function CommentComposer({ me, onSubmit, placeholder = "Write a comment…" }) {
  const [text, setText] = React.useState("");
  const [busy, setBusy] = React.useState(false);
  const submit = async () => {
    const v = text.trim();
    if (!v || busy) return;
    setBusy(true);
    try {
      await onSubmit(v);
      setText("");
    } catch {
      // The caller already showed a toast; keep the text so nothing is lost.
    } finally {
      setBusy(false);
    }
  };
  return (
    <div className="composer">
      <Avatar name={me.name} email={me.email} size={30} />
      <div className="composer-box">
        <AutosizeTextarea
          minRows={2}
          maxRows={10}
          value={text}
          onChange={(e) => setText(e.target.value)}
          onKeyDown={(e) => {
            if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
              e.preventDefault();
              submit();
            }
          }}
          placeholder={placeholder}
          className="composer-input"
        />
        <div className="composer-foot">
          <span className="composer-hint">
            <Kbd>Ctrl</Kbd> + <Kbd>Enter</Kbd> to send
          </span>
          <button className="btn btn-primary btn-sm" disabled={!text.trim() || busy} onClick={submit}>
            {busy ? <Spinner size={13} /> : <IC.Send />} Comment
          </button>
        </div>
      </div>
    </div>
  );
}

/* Activity section (header + filter + timeline + composer). */
function ActivitySection({ item, kind, me, onComment }) {
  const [filter, setFilter] = useLocalStorage("msindaha_activity_filter", "all");
  const commentCount = realComments(item).length;
  const eventCount = (item.comments || []).length - commentCount + 1;
  return (
    <section className="detail-section activity-section">
      <div className="detail-section-head">
        <h4>Activity</h4>
        <Segmented
          size="sm"
          value={filter}
          onChange={setFilter}
          options={[
            { value: "all", label: "All" },
            { value: "comments", label: "Comments", count: commentCount || null },
            { value: "history", label: "History", count: eventCount },
          ]}
        />
      </div>
      <ActivityTimeline item={item} kind={kind} filter={filter} />
      <CommentComposer me={me} onSubmit={onComment} />
    </section>
  );
}

/* Shared "not found" state for detail drawers. */
function DetailNotFound({ what, onClose, loading }) {
  return (
    <div className="detail-missing">
      <div className="drawer-hdr">
        <span />
        <button className="icon-btn" onClick={onClose} aria-label="Close">
          <IC.X />
        </button>
      </div>
      {loading ? (
        <div className="detail-missing-body">
          <Spinner size={22} />
        </div>
      ) : (
        <div className="detail-missing-body">
          <EmptyState icon={IC.Alert} title={`This ${what} isn't available`}>
            It may have been deleted, or it isn't shared with you.
          </EmptyState>
          <button className="btn" onClick={onClose}>
            Close
          </button>
        </div>
      )}
    </div>
  );
}

// Keyboard navigation inside a detail drawer: j/k (or Alt+↓/↑) moves
// between items of the current list; ignored while typing or when another
// overlay (menu, modal) sits on top of the drawer.
function useDetailKeys(active, { onPrev, onNext }) {
  const ref = React.useRef({ onPrev, onNext });
  ref.current = { onPrev, onNext };
  React.useEffect(() => {
    if (!active) return;
    const onKey = (e) => {
      if (isTypingTarget(document.activeElement)) return;
      const top = topLayerId();
      const drawer = document.querySelector(".drawer");
      if (!drawer || drawer.getAttribute("data-layer") !== top) return;
      const next = e.key === "j" || (e.altKey && e.key === "ArrowDown");
      const prev = e.key === "k" || (e.altKey && e.key === "ArrowUp");
      if (next && ref.current.onNext) {
        e.preventDefault();
        ref.current.onNext();
      } else if (prev && ref.current.onPrev) {
        e.preventDefault();
        ref.current.onPrev();
      }
    };
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [active]);
}
