// ============ TaskQuest — Timesheets (weekly grid · capture · approval) ============
const { useState: useStateT, useEffect: useEffectT } = React;

// re-render whenever the timesheet store changes
function useTimeVersion() {
  const [, force] = useStateT(0);
  useEffectT(() => window.TQ_TIME.subscribe(() => force(v => v + 1)), []);
}

function TsStatusBadge({ status }) {
  const meta = {
    draft:     { c: "#878b94", t: "Draft" },
    submitted: { c: "#f2c94c", t: "Submitted" },
    approved:  { c: "#4cb782", t: "Approved" },
    rejected:  { c: "#eb5757", t: "Rejected" },
  }[status] || { c: "#878b94", t: status };
  return <span className={`ts-statusbadge ${status}`}><span className="dot" style={{ background: meta.c }} />{meta.t}</span>;
}

// ---------- week navigator ----------
function WeekNav({ weekStart, setWeekStart }) {
  const T = window.TQ_TIME;
  const isThis = weekStart === T.thisWeekStart();
  return (
    <div className="ts-toolbar">
      <div className="ts-weeknav">
        <button className="ts-week-btn" onClick={() => setWeekStart(T.addDaysISO(weekStart, -7))} title="Previous week"><Ic.ChevLeft size={16} /></button>
        <div>
          <div className="ts-week-label">{T.fmtWeekRange(weekStart)}</div>
          <div className="ts-week-sub">{isThis ? "This week" : "Week of " + T.fmtDay(weekStart)}</div>
        </div>
        <button className="ts-week-btn" onClick={() => setWeekStart(T.addDaysISO(weekStart, 7))} title="Next week"><Ic.ChevRight size={16} /></button>
      </div>
      {!isThis && <button className="ts-today-btn" onClick={() => setWeekStart(T.thisWeekStart())}>This week</button>}
    </div>
  );
}

// ---------- a single editable / read-only hour cell ----------
function HourCell({ consultant, task, project, date, weekend, editable }) {
  const T = window.TQ_TIME;
  const stored = T.getHours(consultant, task, date);
  const [val, setVal] = useStateT(stored ? String(stored) : "");
  if (!editable) {
    return <span className={`ts-num-input${stored ? "" : " zero"}`} style={{ display: "grid", placeItems: "center" }}>{stored || "·"}</span>;
  }
  function commit(s) {
    setVal(s);
    const n = s === "" ? 0 : Number(s);
    if (!isNaN(n)) T.setHours(consultant, task, project, date, n);
  }
  return (
    <input className={`ts-num-input ${weekend ? "weekend" : ""}`} type="number" min="0" max="24" step="0.5"
      value={val} placeholder="·" onChange={e => commit(e.target.value)}
      onFocus={e => e.target.select()} />
  );
}

// ---------- the weekly grid (shared: consultant edits, manager reads) ----------
function WeeklyGrid({ consultant, weekStart, tasks, editable }) {
  const T = window.TQ_TIME;
  const model = T.weekModel(consultant, weekStart, tasks);
  const warn = T.warnings(model);
  const days = model.days;
  const todayI = T.todayISO();

  if (model.projects.length === 0) {
    return (
      <div className="empty-state" style={{ background: "var(--surface)", border: "1px solid var(--border)", borderRadius: "var(--radius-lg)" }}>
        <div className="es-ic"><Ic.Clock size={26} /></div>
        <h3>No tasks to log against</h3>
        <div>{editable ? "Hours can be logged once you have assigned tasks for this week." : "Nothing was logged this week."}</div>
      </div>
    );
  }

  return (
    <div className="ts-grid-wrap">
      <div className="ts-scroll">
        <div className="ts-grid">
          {/* header */}
          <div className="ts-row head">
            <div className="ts-cell"><span className="ts-th">Task</span></div>
            <div className="ts-cell"><span className="ts-th">Activity</span></div>
            <div className="ts-cell num"><span className="ts-th">Billable</span></div>
            {days.map((d, i) => (
              <div className="ts-cell num" key={d}>
                <div className={`ts-th-day ${i >= 5 ? "weekend" : ""} ${d === todayI ? "is-today" : ""}`}>
                  <span className="d">{T.dayLabel(d)}</span>
                  <span className="n">{T.dayNum(d)}</span>
                </div>
              </div>
            ))}
            <div className="ts-cell num"><span className="ts-th">Total</span></div>
          </div>

          {/* projects + tasks */}
          {model.projects.map(g => (
            <React.Fragment key={g.key}>
              <div className="ts-row proj">
                <div className="ts-cell" style={{ gridColumn: "1 / -2" }}>
                  <span className="ts-proj-name"><span className="pdot" style={{ background: g.color }} />{g.name}</span>
                  <span className="ts-proj-sub">{g.tasks.length} task{g.tasks.length === 1 ? "" : "s"}</span>
                </div>
                <div className="ts-cell num"><span className="ts-proj-total">{g.total ? g.total + "h" : "—"}</span></div>
              </div>
              {g.tasks.map(row => (
                <div className="ts-row task" key={row.task.id}>
                  <div className="ts-cell">
                    <div className="ts-task-name">
                      <div className="ts-task-t" title={row.task.name}>{row.task.name}</div>
                      <div className="ts-task-id">{row.task.id}</div>
                    </div>
                  </div>
                  <div className="ts-cell">
                    <select className="ts-actsel" value={row.meta.activity} disabled={!editable}
                      onChange={e => T.setMeta(consultant, row.task.id, { activity: e.target.value })}>
                      <option value="">— Select —</option>
                      {T.ACTIVITIES.map(a => <option key={a.key} value={a.key}>{a.name}</option>)}
                    </select>
                  </div>
                  <div className="ts-cell num">
                    <button className={`ts-bill ${row.meta.billable ? "on" : ""}`} disabled={!editable}
                      onClick={() => editable && T.setMeta(consultant, row.task.id, { billable: !row.meta.billable })}
                      title={row.meta.billable ? "Billable" : "Non-billable"}>
                      {row.meta.billable ? <><Ic.Check size={11} />Bill</> : "Non-bill"}
                    </button>
                  </div>
                  {days.map((d, i) => (
                    <div className="ts-cell num" key={d}>
                      <HourCell consultant={consultant} task={row.task.id} project={row.task.project}
                        date={d} weekend={i >= 5} editable={editable} key={consultant + "|" + row.task.id + "|" + d} />
                    </div>
                  ))}
                  <div className="ts-cell num"><span className="ts-row-total">{row.total || "—"}</span></div>
                </div>
              ))}
            </React.Fragment>
          ))}

          {/* footer totals */}
          <div className="ts-row foot">
            <div className="ts-cell" style={{ gridColumn: "1 / 4" }}><span className="ts-foot-label">Daily total</span></div>
            {days.map(d => (
              <div className="ts-cell num" key={d}>
                <span className={`ts-foot-day ${warn.days[d] ? "warn" : ""}`}>{model.dayTotals[d] || "—"}</span>
              </div>
            ))}
            <div className="ts-cell num"><span className={`ts-foot-total ${warn.week ? "warn" : ""}`}>{model.weekTotal || 0}h</span></div>
          </div>
        </div>
      </div>
    </div>
  );
}

// ---------- CONSULTANT: my weekly timesheet ----------
function ConsultantTimesheet({ role, tasks, addToast, pushNotif }) {
  useTimeVersion();
  const T = window.TQ_TIME;
  const [weekStart, setWeekStart] = useStateT(() => T.thisWeekStart());
  const model = T.weekModel(role, weekStart, tasks);
  const warn = T.warnings(model);
  const sheet = T.statusOf(role, weekStart);
  const locked = T.isLocked(role, weekStart);
  const ROLES = window.TQ.ROLES;

  function submit() {
    if (model.weekTotal <= 0) { addToast("Log some hours before submitting", Ic.Alert, "#eb5757"); return; }
    T.submitWeek(role, weekStart, "");
    const proj = model.projects[0] ? model.projects[0].key : null;
    pushNotif({ type: "done", who: role, project: proj, forRoles: ["pm", "dm"],
      text: `<b>${ROLES[role] ? ROLES[role].name : "A consultant"}</b> submitted a timesheet (${T.fmtWeekRange(weekStart)}) — ${model.weekTotal}h, needs approval` });
    addToast("Timesheet submitted for approval", Ic.Send, "#f2c94c");
  }

  const statusBanner = (() => {
    if (sheet.status === "submitted") return (
      <div className="ts-status submitted">
        <span className="ts-status-ic" style={{ background: "rgba(242,201,76,0.2)" }}><Ic.Clock size={16} /></span>
        <div className="ts-status-main">Submitted — awaiting manager approval
          <div className="ts-status-sub">{model.weekTotal}h logged · submitted for {T.fmtWeekRange(weekStart)}. Locked until reviewed.</div></div>
      </div>
    );
    if (sheet.status === "approved") return (
      <div className="ts-status approved">
        <span className="ts-status-ic" style={{ background: "rgba(76,183,130,0.2)" }}><Ic.CheckCircle size={16} /></span>
        <div className="ts-status-main">Approved by {ROLES[sheet.decidedBy] ? ROLES[sheet.decidedBy].name : "your manager"}
          <div className="ts-status-sub">{model.weekTotal}h signed off for {T.fmtWeekRange(weekStart)}.</div></div>
      </div>
    );
    if (sheet.status === "rejected") return (
      <div className="ts-status rejected">
        <span className="ts-status-ic" style={{ background: "rgba(235,87,87,0.18)" }}><Ic.Alert size={16} /></span>
        <div className="ts-status-main">Returned for changes by {ROLES[sheet.decidedBy] ? ROLES[sheet.decidedBy].name : "your manager"}
          <div className="ts-status-sub">{sheet.reason ? "“" + sheet.reason + "” — " : ""}Update your hours and resubmit.</div></div>
      </div>
    );
    return (
      <div className="ts-status draft">
        <span className="ts-status-ic" style={{ background: "var(--surface)" }}><Ic.Edit size={15} /></span>
        <div className="ts-status-main">Draft — log your hours, then submit the week
          <div className="ts-status-sub">Type hours into each day. {model.weekTotal}h so far this week.</div></div>
      </div>
    );
  })();

  return (
    <div className="ts-wrap">
      <WeekNav weekStart={weekStart} setWeekStart={setWeekStart} />
      {statusBanner}
      <WeeklyGrid consultant={role} weekStart={weekStart} tasks={tasks} editable={!locked} />
      {(warn.week || Object.keys(warn.days).length > 0) && (
        <div className="ts-warnnote"><Ic.Alert size={14} />
          {warn.week ? `This week exceeds ${T.WARN_WEEK}h.` : `One or more days exceed ${T.WARN_DAY}h.`} You can still submit — just confirming it's intentional.</div>
      )}
      <div className="ts-actions">
        <span className="ts-billsum">Week total <b>{model.weekTotal}h</b> · <b>{model.billable}h</b> billable</span>
        <span className="spacer" />
        {!locked && (
          <button className="btn btn-primary" disabled={model.weekTotal <= 0} onClick={submit}>
            <Ic.Send size={15} />{sheet.status === "rejected" ? "Resubmit week" : "Submit week for approval"}
          </button>
        )}
        {sheet.status === "submitted" && <span className="ts-meta-note"><Ic.Lock size={13} style={{ verticalAlign: "-2px", marginRight: 5 }} />Locked — awaiting review</span>}
      </div>
    </div>
  );
}

// ---------- MANAGER: review queue + export ----------
function ManagerTimesheets({ role, project, tasks, addToast, pushNotif }) {
  useTimeVersion();
  const T = window.TQ_TIME;
  const { ROLES, PROJECTS, CONSULTANTS, projectsOf } = window.TQ;
  const [weekStart, setWeekStart] = useStateT(() => T.thisWeekStart());
  const [openId, setOpenId] = useStateT(null);

  // consultants in scope
  const consultants = CONSULTANTS.filter(c => {
    if (project === "all") return true;
    return projectsOf(ROLES[c]).indexOf(project) >= 0;
  });

  const rows = consultants.map(c => {
    const model = T.weekModel(c, weekStart, tasks);
    const sheet = T.statusOf(c, weekStart);
    // scope hours to the selected project when not 'all'
    let hours = model.weekTotal, billable = model.billable;
    if (project !== "all") {
      const g = model.projects.find(p => p.key === project);
      hours = g ? g.total : 0;
      billable = g ? g.tasks.reduce((a, r) => a + (r.meta.billable ? r.total : 0), 0) : 0;
    }
    return { c, model, sheet, hours, billable };
  }).filter(r => r.hours > 0 || r.sheet.status !== "draft");

  const order = { submitted: 0, rejected: 1, draft: 2, approved: 3 };
  rows.sort((a, b) => (order[a.sheet.status] - order[b.sheet.status]) ||
    (ROLES[a.c] ? ROLES[a.c].name : a.c).localeCompare(ROLES[b.c] ? ROLES[b.c].name : b.c));

  const submittedCount = rows.filter(r => r.sheet.status === "submitted").length;
  const totalHours = rows.reduce((a, r) => a + r.hours, 0);
  const billableHours = rows.reduce((a, r) => a + r.billable, 0);

  const open = openId ? rows.find(r => r.c === openId) : null;

  function decideApprove(c) {
    T.approveWeek(c, weekStart, role);
    pushNotif({ type: "approved", who: role, project: project === "all" ? null : project, forRoles: [c],
      text: `Your timesheet for ${T.fmtWeekRange(weekStart)} was approved by <b>${ROLES[role] ? ROLES[role].name : "your manager"}</b>` });
    addToast(`Approved ${ROLES[c] ? ROLES[c].short : ""}'s timesheet`, Ic.CheckCircle, "#4cb782");
    setOpenId(null);
  }
  function decideReject(c, reason) {
    T.rejectWeek(c, weekStart, role, reason);
    pushNotif({ type: "rejected", who: role, project: project === "all" ? null : project, forRoles: [c],
      text: `Your timesheet for ${T.fmtWeekRange(weekStart)} was returned for changes${reason ? " — “" + reason + "”" : ""}` });
    addToast(`Returned ${ROLES[c] ? ROLES[c].short : ""}'s timesheet`, Ic.Arrow, "#eb5757");
    setOpenId(null);
  }
  function exportCsv() {
    const n = T.exportCSV(project, weekStart, tasks, consultants);
    addToast(n ? `Exported ${n} row${n === 1 ? "" : "s"} to CSV` : "No hours to export this week", Ic.Send, "#16a394");
  }

  const scopeName = project === "all" ? "All projects" : (PROJECTS[project] ? PROJECTS[project].name : "");

  return (
    <div className="ts-wrap">
      <WeekNav weekStart={weekStart} setWeekStart={setWeekStart} />
      <div className="ts-review-head">
        <div className="ts-mini-stats">
          <div className="ts-mini-stat"><div className="v">{submittedCount}</div><div className="l">To review</div></div>
          <div className="ts-mini-stat"><div className="v">{totalHours}h</div><div className="l">Logged</div></div>
          <div className="ts-mini-stat"><div className="v">{billableHours}h</div><div className="l">Billable</div></div>
        </div>
        <span className="spacer" />
        <button className="btn btn-ghost" onClick={exportCsv}><Ic.Send size={14} />Export {scopeName} · CSV</button>
      </div>

      {rows.length === 0 ? (
        <div className="empty-state">
          <div className="es-ic"><Ic.Clock size={26} /></div>
          <h3>Nothing logged yet</h3>
          <div>Timesheets appear here as consultants log and submit hours for this week.</div>
        </div>
      ) : (
        <div className="ts-review">
          {rows.map(r => {
            const projs = projectsOf(ROLES[r.c]).map(k => PROJECTS[k]).filter(Boolean);
            const pj = projs[0];
            return (
              <div className="ts-review-card" key={r.c} onClick={() => setOpenId(r.c)}>
                <div className="ts-rc-person">
                  <Avatar who={r.c} size="md" />
                  <div style={{ minWidth: 0 }}>
                    <div className="ts-rc-name">{ROLES[r.c] ? ROLES[r.c].name : r.c}</div>
                    {pj && <div className="ts-rc-proj"><span className="pdot" style={{ background: pj.color }} />{projs.map(p => p.name).join(", ")}</div>}
                  </div>
                </div>
                <div><TsStatusBadge status={r.sheet.status} /></div>
                <div className="ts-rc-hours ts-rc-hide">{r.hours}h <span>· {r.billable}h bill</span></div>
                <div className="ts-rc-hide" style={{ fontSize: 12, color: "var(--faint)", fontWeight: 600 }}>
                  {r.sheet.status === "submitted" ? "Awaiting your review"
                    : r.sheet.status === "approved" ? "Signed off"
                    : r.sheet.status === "rejected" ? "Returned for changes" : "In progress"}
                </div>
                <div className="ts-rc-chevron"><Ic.ChevRight size={18} /></div>
              </div>
            );
          })}
        </div>
      )}

      {open && (
        <TimesheetReviewModal consultant={open.c} weekStart={weekStart} tasks={tasks} sheet={open.sheet}
          canDecide={true} onApprove={decideApprove} onReject={decideReject} onClose={() => setOpenId(null)} />
      )}
    </div>
  );
}

// ---------- review modal (read-only grid + approve/reject) ----------
function TimesheetReviewModal({ consultant, weekStart, tasks, sheet, canDecide, onApprove, onReject, onClose }) {
  const T = window.TQ_TIME;
  const ROLES = window.TQ.ROLES;
  const [rejecting, setRejecting] = useStateT(false);
  const [reason, setReason] = useStateT("");
  const model = T.weekModel(consultant, weekStart, tasks);
  const who = ROLES[consultant];
  const canAct = canDecide && sheet.status === "submitted";

  return (
    <ModalShell icon={Ic.Clock} iconColor="#5E6AD2" title={(who ? who.name : consultant) + " · Timesheet"} wide
      desc={<span style={{ display: "inline-flex", gap: 8, alignItems: "center" }}>{T.fmtWeekRange(weekStart)}<span style={{ color: "var(--border-strong)" }}>·</span>{model.weekTotal}h · {model.billable}h billable</span>}
      onClose={onClose}
      footer={
        canAct ? (
          rejecting ? (
            <>
              <button className="btn btn-ghost" onClick={() => setRejecting(false)}>Cancel</button>
              <span className="spacer" />
              <button className="btn btn-soft-danger" onClick={() => onReject(consultant, reason.trim())}><Ic.Arrow size={15} />Return for changes</button>
            </>
          ) : (
            <>
              <button className="btn btn-soft-danger" onClick={() => setRejecting(true)}><Ic.X size={15} />Reject</button>
              <span className="spacer" />
              <button className="btn btn-success" onClick={() => onApprove(consultant)}><Ic.Check size={15} />Approve timesheet</button>
            </>
          )
        ) : (
          <><span className="spacer" /><button className="btn btn-ghost" onClick={onClose}>Close</button></>
        )
      }>

      {sheet.status === "approved" && (
        <div className="approval-box done">
          <div className="approval-title"><Ic.CheckCircle size={15} style={{ color: "var(--green)" }} />Approved</div>
          <div className="approval-meta">Signed off by {ROLES[sheet.decidedBy] ? ROLES[sheet.decidedBy].name : "a manager"}.</div>
        </div>
      )}
      {sheet.status === "rejected" && (
        <div className="approval-box" style={{ background: "var(--red-soft)", borderColor: "rgba(235,87,87,0.35)" }}>
          <div className="approval-title"><Ic.Alert size={15} style={{ color: "var(--red)" }} />Returned for changes</div>
          <div className="approval-meta">{sheet.reason ? "“" + sheet.reason + "”" : "Sent back to the consultant to revise."}</div>
        </div>
      )}
      {sheet.status === "submitted" && sheet.note && (
        <div className="approval-box">
          <div className="approval-title"><Ic.Msg size={15} style={{ color: "#b88a00" }} />Note from {who ? who.short : "consultant"}</div>
          <div className="approval-meta">{sheet.note}</div>
        </div>
      )}

      <div className="ts-modal-grid">
        <WeeklyGrid consultant={consultant} weekStart={weekStart} tasks={tasks} editable={false} />
      </div>

      {rejecting && (
        <div className="ts-reject-box field">
          <label className="field-label">Reason for returning <span style={{ color: "var(--faint)", fontWeight: 500 }}>· optional</span></label>
          <textarea className="textarea" autoFocus placeholder="e.g. Tuesday's 11h looks high — please confirm or split it." value={reason} onChange={e => setReason(e.target.value)} />
        </div>
      )}
    </ModalShell>
  );
}

// ---------- per-card mini logger (inside the task detail modal) ----------
function TaskWeekLogger({ task, role }) {
  useTimeVersion();
  const T = window.TQ_TIME;
  const weekStart = T.thisWeekStart();
  const locked = T.isLocked(role, weekStart);
  const days = T.weekDays(weekStart);
  const todayI = T.todayISO();
  let weekTotal = 0;
  days.forEach(d => { weekTotal += T.getHours(role, task.id, d); });
  const sheet = T.statusOf(role, weekStart);

  return (
    <div style={{ marginBottom: 18 }}>
      <div className="section-label" style={{ display: "flex", alignItems: "center", gap: 8 }}>
        Log hours · this week
        <span style={{ marginLeft: "auto", textTransform: "none", letterSpacing: 0 }}><TsStatusBadge status={sheet.status} /></span>
      </div>
      <div className="ts-grid-wrap">
        <div className="ts-scroll">
          <div className="ts-grid" style={{ minWidth: 520 }}>
            <div className="ts-row head" style={{ gridTemplateColumns: "repeat(7, 1fr) 64px" }}>
              {days.map((d, i) => (
                <div className="ts-cell num" key={d}>
                  <div className={`ts-th-day ${i >= 5 ? "weekend" : ""} ${d === todayI ? "is-today" : ""}`}>
                    <span className="d">{T.dayLabel(d)}</span><span className="n">{T.dayNum(d)}</span>
                  </div>
                </div>
              ))}
              <div className="ts-cell num"><span className="ts-th">Total</span></div>
            </div>
            <div className="ts-row task" style={{ gridTemplateColumns: "repeat(7, 1fr) 64px" }}>
              {days.map((d, i) => (
                <div className="ts-cell num" key={d}>
                  <HourCell consultant={role} task={task.id} project={task.project} date={d} weekend={i >= 5}
                    editable={!locked} key={role + "|" + task.id + "|" + d} />
                </div>
              ))}
              <div className="ts-cell num"><span className="ts-row-total">{weekTotal || "—"}</span></div>
            </div>
          </div>
        </div>
      </div>
      <div style={{ fontSize: 12, color: "var(--muted)", marginTop: 8 }}>
        {locked ? "This week's timesheet is locked while it's under review." : "Hours roll up into your weekly timesheet. Submit the full week from the Timesheet tab."}
      </div>
    </div>
  );
}

Object.assign(window, {
  ConsultantTimesheet, ManagerTimesheets, TimesheetReviewModal, TaskWeekLogger,
  WeeklyGrid, WeekNav, TsStatusBadge, HourCell,
});
