/* ============================================================
   Balance utilities + Employee/CEO dashboard
   ============================================================ */
const { useState, useEffect, useRef } = React;
const round2 = (n) => Math.round(n * 100) / 100;

// Vacation entitlement for a given year, pro-rated by start date.
// Rule: 1/12 of the annual allowance per employed month in `year`.
// Mid-month rule (15th cut-off): joining on or before the 15th counts that
// month as full; joining on the 16th or later, the start month doesn't count.
function proratedAllowance(person, year = VP_DATA.YEAR) {
  const base = (person && person.allowance != null) ? person.allowance : VP_DATA.ALLOWANCE;
  if (!person || !person.startDate) return base;
  const [sy, sm, sd] = person.startDate.split("-").map(Number);
  if (sy < year) return base;   // started before this year → full entitlement
  if (sy > year) return 0;      // starts in a future year → none yet this year
  // After the 15th, entitlement starts counting from the next month.
  const firstCountedMonth = (sd > 15) ? sm + 1 : sm;
  const monthsEmployed = Math.max(0, 12 - firstCountedMonth + 1);
  return round2((base * monthsEmployed) / 12);
}

// Balance-counting vacation days (approved/pending) inside a date window.
function vacationDaysInWindow(personId, requests, status, loISO, hiISO) {
  return requests
    .filter((r) => r.person === personId && r.status === status
      && VP_DATA.leaveTypes[r.type] && VP_DATA.leaveTypes[r.type].countsToBalance)
    .reduce((s, r) => s + workingDaysInWindow(r, loISO, hiISO), 0);
}

// Year-aware balance with carryover.
// Company rule: unused days from the previous year carry into this year and
// stay usable until 31 March; after that they expire. Leave taken in Q1 draws
// from the carryover first, then from the new entitlement.
function balanceFor(personId, requests, year = VP_DATA.YEAR) {
  const person = VP_DATA.byId[personId];
  const ent = proratedAllowance(person, year);
  const jan1 = `${year}-01-01`, mar31 = `${year}-03-31`, dec31 = `${year}-12-31`;

  // Carryover from last year — only for years the tool actually tracked.
  let carryIn = 0;
  if ((year - 1) >= VP_DATA.TRACKING_SINCE) {
    const prevEnt = proratedAllowance(person, year - 1);
    const prevUsed = vacationDaysInWindow(personId, requests, "approved", `${year - 1}-01-01`, `${year - 1}-12-31`);
    carryIn = Math.max(0, round2(prevEnt - prevUsed));
  }

  const usedY = vacationDaysInWindow(personId, requests, "approved", jan1, dec31);
  const usedQ1 = vacationDaysInWindow(personId, requests, "approved", jan1, mar31);
  const pending = vacationDaysInWindow(personId, requests, "pending", jan1, dec31);

  const carryoverSpent = Math.min(carryIn, usedQ1);
  const entitlementRemaining = ent - (usedY - carryoverSpent);
  const carryoverActive = TODAY <= mar31;
  const carryoverRemaining = carryoverActive ? round2(carryIn - carryoverSpent) : 0;
  const remaining = round2(entitlementRemaining + carryoverRemaining);
  const total = round2(usedY + remaining); // live pool: entitlement + still-valid carryover

  return {
    used: usedY, pending, remaining, allowance: ent, total,
    carryIn, carryoverRemaining, carryoverActive, carryoverDeadline: mar31,
  };
}

/* Ring gauge */
function BalanceRing({ used, pending, allowance, remaining, size = 168 }) {
  const r = size / 2 - 13;
  const C = 2 * Math.PI * r;
  const usedFrac = allowance > 0 ? Math.min(used / allowance, 1) : 0;
  const pendFrac = allowance > 0 ? Math.min((used + pending) / allowance, 1) : 0;
  const left = remaining != null ? remaining : (allowance - used);
  return (
    <div style={{ position: "relative", width: size, height: size }}>
      <svg width={size} height={size} style={{ transform: "rotate(-90deg)" }}>
        <circle cx={size/2} cy={size/2} r={r} stroke="var(--paper-2)" strokeWidth="13" fill="none" />
        {/* pending (lighter) */}
        <circle cx={size/2} cy={size/2} r={r} stroke="var(--st-pending)" strokeWidth="13" fill="none"
          strokeLinecap="round" strokeDasharray={C} strokeDashoffset={C * (1 - pendFrac)}
          opacity="0.32" style={{ transition: "stroke-dashoffset 0.8s cubic-bezier(0.2,0.7,0.2,1)" }} />
        {/* used */}
        <circle cx={size/2} cy={size/2} r={r} stroke="var(--accent)" strokeWidth="13" fill="none"
          strokeLinecap="round" strokeDasharray={C} strokeDashoffset={C * (1 - usedFrac)}
          style={{ transition: "stroke-dashoffset 0.9s cubic-bezier(0.2,0.7,0.2,1)" }} />
      </svg>
      <div style={{ position: "absolute", inset: 0, display: "grid", placeItems: "center", textAlign: "center" }}>
        <div>
          <div style={{ fontFamily: "var(--font-display)", fontSize: 42, fontWeight: 600, letterSpacing: "-0.03em", lineHeight: 1, color: "var(--ink)" }}>
            {left}
          </div>
          <div style={{ fontSize: 12.5, color: "var(--ink-3)", marginTop: 4, fontWeight: 600 }}>days left</div>
        </div>
      </div>
    </div>
  );
}

function StatChip({ value, label, color }) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
      <span style={{ width: 9, height: 9, borderRadius: 3, background: color, flex: "0 0 auto" }} />
      <div>
        <div style={{ fontWeight: 700, fontSize: 16, fontFamily: "var(--font-display)", color: "var(--ink)" }}>{value}</div>
        <div style={{ fontSize: 12, color: "var(--ink-3)" }}>{label}</div>
      </div>
    </div>
  );
}

/* A single request row */
function RequestRow({ req, showPerson, onClick, right }) {
  const [hover, setHover] = useState(false);
  const person = VP_DATA.byId[req.person];
  const rep = req.replacement ? VP_DATA.byId[req.replacement] : null;
  return (
    <div onClick={onClick} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      style={{
        display: "flex", alignItems: "center", gap: 14, padding: "13px 14px",
        background: hover && onClick ? "var(--surface-2)" : "transparent",
        borderRadius: "var(--r-md)", cursor: onClick ? "pointer" : "default",
        transition: "background 0.14s ease",
      }}>
      {showPerson && <Avatar person={person} size={38} />}
      <div style={{ width: 4, alignSelf: "stretch", borderRadius: 4, background: VP_DATA.leaveTypes[req.type].color, flex: "0 0 auto", minHeight: 34 }} />
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 9, flexWrap: "wrap" }}>
          <span style={{ fontWeight: 600, fontSize: 15, color: "var(--ink)" }}>
            {showPerson ? `${person.first} ${person.last}` : VP_DATA.leaveTypes[req.type].label}
          </span>
          {showPerson && <TypeTag type={req.type} size="sm" />}
        </div>
        <div style={{ fontSize: 13, color: "var(--ink-3)", marginTop: 3, display: "flex", gap: 12, flexWrap: "wrap" }}>
          <span style={{ display: "inline-flex", alignItems: "center", gap: 5 }}>
            <Icon name="calendar" size={13} /> {fmtRange(req.from, req.to)} · {workingDays(req)}{workingDays(req) === 1 ? " day" : " days"}
          </span>
          {rep && <span style={{ display: "inline-flex", alignItems: "center", gap: 5 }}>
            <Icon name="swap" size={13} /> {rep.first} {rep.last}
          </span>}
        </div>
      </div>
      {right || <StatusPill status={req.status} />}
    </div>
  );
}

function SectionTitle({ children, count, action }) {
  return (
    <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 4 }}>
      <h3 style={{ fontSize: 17, display: "flex", alignItems: "center", gap: 9 }}>
        {children}
        {count != null && <span style={{ fontSize: 13, color: "var(--ink-4)", fontWeight: 600, fontFamily: "var(--font-body)" }}>{count}</span>}
      </h3>
      {action}
    </div>
  );
}

/* Who's out within a window */
function whoIsOut(requests, fromISO_, toISO_) {
  const winA = parseISO(fromISO_), winB = parseISO(toISO_);
  return requests.filter((r) => r.status === "approved")
    .filter((r) => parseISO(r.from) <= winB && parseISO(r.to) >= winA);
}

function Dashboard({ user, requests, onNewRequest, onOpenRequest, onGoto }) {
  const isCeo = user.role === "ceo";
  const narrow = useIsNarrow(820);
  const coCeo = VP_DATA.ceos.find((c) => c.id !== user.id);
  const bal = balanceFor(user.id, requests);
  const mine = requests.filter((r) => r.person === user.id)
    .sort((a, b) => (a.status === "pending" ? -1 : 1) - (b.status === "pending" ? -1 : 1) || parseISO(b.from) - parseISO(a.from));
  const myUpcoming = requests.filter((r) => r.person === user.id && r.status === "approved" && parseISO(r.to) >= parseISO(TODAY))
    .sort((a, b) => parseISO(a.from) - parseISO(b.from));
  const pending = requests.filter((r) => r.status === "pending");

  // this week window
  const weekEnd = toISO(addDays(parseISO(TODAY), 7));
  const outThisWeek = whoIsOut(requests, TODAY, weekEnd).filter((r) => r.person !== user.id);

  return (
    <div className="vp-fade-up" style={{ display: "grid", gap: "var(--gap)" }}>
      {/* Greeting */}
      <div style={{ display: "flex", alignItems: "flex-end", justifyContent: "space-between", gap: 20, flexWrap: "wrap" }}>
        <div>
          <h1 style={{ fontSize: 30 }}>Hi {user.first}</h1>
          <p style={{ color: "var(--ink-3)", margin: "6px 0 0", fontSize: 15 }}>
            {isCeo
              ? (pending.length ? `${pending.length} request${pending.length === 1 ? "" : "s"} to review.` : "No requests to review.")
              : `${bal.remaining} of ${bal.total} days left this year.`}
          </p>
        </div>
        <Button size="lg" icon="plus" onClick={onNewRequest}>Request time off</Button>
      </div>

      {(() => {
        const balanceCard = (
          <Card style={{ display: "flex", flexDirection: "column", gap: 18 }}>
            <SectionTitle>{isCeo ? "Your balance" : "Vacation balance"}</SectionTitle>
            <div style={{ display: "flex", alignItems: "center", gap: isCeo ? 18 : 22 }}>
              <BalanceRing used={bal.used} pending={bal.pending} allowance={bal.total} remaining={bal.remaining} size={isCeo ? 118 : 168} />
              <div style={{ display: "grid", gap: isCeo ? 13 : 16 }}>
                <StatChip value={bal.used} label="days used" color="var(--accent)" />
                <StatChip value={bal.pending} label="days pending" color="var(--st-pending)" />
                <StatChip value={bal.allowance} label={bal.allowance !== user.allowance ? "allowance this year" : "annual allowance"} color="var(--paper-2)" />
                {bal.carryIn > 0 && <StatChip value={bal.carryoverRemaining} label={bal.carryoverActive ? "carried over · use by Mar 31" : "carryover expired"} color="var(--st-approved)" />}
              </div>
            </div>
            {bal.carryoverRemaining > 0 && bal.carryoverActive && (
              <div style={{ display: "flex", gap: 8, alignItems: "flex-start", fontSize: 12.5, color: "var(--ink-3)", lineHeight: 1.45, background: "var(--surface-2)", padding: "10px 12px", borderRadius: "var(--r-sm)" }}>
                <Icon name="info" size={16} style={{ flex: "0 0 auto", marginTop: 1, color: "var(--st-approved)" }} />
                <span><strong>{bal.carryoverRemaining}</strong> day{bal.carryoverRemaining === 1 ? "" : "s"} carried over from {VP_DATA.YEAR - 1} — use by 31 March {VP_DATA.YEAR}, then they expire.</span>
              </div>
            )}
          </Card>
        );
        const secondaryCard = isCeo ? (
          <Card style={{ display: "flex", flexDirection: "column" }}>
            <SectionTitle count={pending.length} action={
              <Button size="sm" variant="ghost" iconRight="arrowRight" onClick={() => onGoto("approvals")}>Open inbox</Button>
            }>Awaiting approval</SectionTitle>
            <div style={{ marginTop: 6, display: "grid", gap: 2, marginLeft: -6, marginRight: -6 }}>
              {pending.slice(0, 4).map((r) => (
                <RequestRow key={r.id} req={r} showPerson onClick={() => onOpenRequest(r)} />
              ))}
              {pending.length === 0 && <Empty>Nothing awaiting approval.</Empty>}
            </div>
          </Card>
        ) : (
          <Card style={{ display: "flex", flexDirection: "column" }}>
            <SectionTitle count={myUpcoming.length}>Your upcoming time off</SectionTitle>
            <div style={{ marginTop: 6, display: "grid", gap: 2, marginLeft: -6, marginRight: -6 }}>
              {myUpcoming.slice(0, 3).map((r) => (
                <RequestRow key={r.id} req={r} onClick={() => onOpenRequest(r)} />
              ))}
              {myUpcoming.length === 0 && <Empty>No upcoming time off.</Empty>}
            </div>
          </Card>
        );
        // CEO: lead with the approval queue (their job), balance demoted to the side.
        // Employee: balance leads, upcoming alongside.
        return (
          <div style={{ display: "grid", gridTemplateColumns: narrow ? "1fr" : (isCeo ? "1fr 340px" : "300px 1fr"), gap: "var(--gap)", alignItems: "start" }}>
            {isCeo ? <>{secondaryCard}{balanceCard}</> : <>{balanceCard}{secondaryCard}</>}
          </div>
        );
      })()}

      {/* Bottom row */}
      <div style={{ display: "grid", gridTemplateColumns: narrow ? "1fr" : "1.4fr 1fr", gap: "var(--gap)" }}>
        {/* My requests */}
        <Card style={{ display: "flex", flexDirection: "column" }}>
          <SectionTitle count={mine.length} action={
            <Button size="sm" variant="ghost" iconRight="arrowRight" onClick={() => onGoto("calendar")}>Team calendar</Button>
          }>{isCeo ? "Your requests" : "My requests"}</SectionTitle>
          <div style={{ marginTop: 6, display: "grid", gap: 2, marginLeft: -6, marginRight: -6, maxHeight: 320, overflowY: "auto" }}>
            {mine.map((r) => <RequestRow key={r.id} req={r} onClick={() => onOpenRequest(r)} />)}
            {mine.length === 0 && <Empty>No requests yet.</Empty>}
          </div>
        </Card>

        {/* Who's out this week */}
        <Card style={{ display: "flex", flexDirection: "column" }}>
          <SectionTitle count={outThisWeek.length}>Out this week</SectionTitle>
          <div style={{ marginTop: 10, display: "grid", gap: 12 }}>
            {outThisWeek.slice(0, 6).map((r) => {
              const p = VP_DATA.byId[r.person];
              return (
                <div key={r.id} style={{ display: "flex", alignItems: "center", gap: 12 }}>
                  <Avatar person={p} size={36} />
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontWeight: 600, fontSize: 14 }}>{p.first} {p.last}</div>
                    <div style={{ fontSize: 12.5, color: "var(--ink-3)" }}>{fmtRange(r.from, r.to)}</div>
                  </div>
                  <TypeTag type={r.type} withLabel={false} size="sm" />
                </div>
              );
            })}
            {outThisWeek.length === 0 && <Empty>Everyone's in this week.</Empty>}
          </div>
        </Card>
      </div>
    </div>
  );
}

function Empty({ children }) {
  return <div style={{ padding: "22px 14px", textAlign: "center", color: "var(--ink-4)", fontSize: 14 }}>{children}</div>;
}

Object.assign(window, { Dashboard, BalanceRing, balanceFor, proratedAllowance, RequestRow, SectionTitle, Empty, whoIsOut, StatChip });
