// data-loader.jsx — fetches getTeamData, populates window.YD in the shape the
// v3 design's components expect (mirrors the structure built by the design's
// v3-data.jsx mock). Exposes a useTeamData() hook that components call.

const { useState: dlUseState, useEffect: dlUseEffect, useCallback: dlUseCallback } = React;

// Severity meta — mirrors design v3-data.jsx.
const SEV_META = {
  critical: { label: 'Critical', color: '#b91c1c', bg: '#fef2f2', border: '#fecaca', priority: 1 },
  high:     { label: 'High',     color: '#b45309', bg: '#fffbeb', border: '#fde68a', priority: 2 },
  watch:    { label: 'Watch',    color: '#a16207', bg: '#fefce8', border: '#fef08a', priority: 3 },
  ok:       { label: 'On track', color: '#15803d', bg: '#f0fdf4', border: '#bbf7d0', priority: 4 },
  leave:    { label: 'On leave', color: '#1d4ed8', bg: '#eff6ff', border: '#bfdbfe', priority: 5 },
};

const DAYS = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'];
function todayIdx() {
  // luxon-style: Monday=0..Sunday=6
  return (new Date().getDay() + 6) % 7;
}

function buildTodayBuckets(members, idx) {
  const dayShift = (m) => m.dailyShifts && m.dailyShifts[idx] ? m.dailyShifts[idx] : null;
  return {
    completed:     members.filter(m => { const d = dayShift(m); return d && (d.status === 'Shift Done' || d.status === 'Exceeded' || d.isDone || d.isExceeded); }),
    working:       members.filter(m => { const d = dayShift(m); return d && (d.isInProgress || d.status === 'In Progress'); }),
    incomplete:    members.filter(m => { const d = dayShift(m); return d && (d.isIncomplete || d.status === 'Incomplete'); }),
    notYetStarted: members.filter(m => m.shiftNotYetStarted),
    lateNoClock:   members.filter(m => m.notClockedIn),
    onLeave:       members.filter(m => m.isOnLeave),
    dayOff:        members.filter(m => { const d = dayShift(m); return d && d.isDayOff; }),
  };
}

function dateLabels() {
  const monday = new Date();
  monday.setDate(monday.getDate() - ((monday.getDay() + 6) % 7));
  const out = [];
  for (let i = 0; i < 7; i++) {
    const d = new Date(monday);
    d.setDate(monday.getDate() + i);
    out.push(d.toLocaleDateString(undefined, { day: 'numeric', month: 'short' }));
  }
  return out;
}

function freshnessFromResp(freshness) {
  if (!freshness) {
    return { quidloMinutesAgo: null, kpiMinutesAgo: null, quidloStaleThreshold: 15, kpiStaleThreshold: 240 };
  }
  return {
    quidloMinutesAgo: freshness.quidloMinutesAgo,
    kpiMinutesAgo: freshness.kpiMinutesAgo,
    quidloStaleThreshold: 15,
    kpiStaleThreshold: 240,
  };
}

// Pace trend placeholder — backend doesn't yet ship 5-week trend. For now
// just show this week's average; UI handles a single-point series gracefully.
function pacePlaceholder(teamPace) {
  return [
    { week: '−4w', pace: teamPace },
    { week: '−3w', pace: teamPace },
    { week: '−2w', pace: teamPace },
    { week: '−1w', pace: teamPace },
    { week: 'This', pace: teamPace },
  ];
}

function populateWindowYD(resp) {
  const idx = todayIdx();
  const members = resp.members || [];
  window.YD = {
    DAYS,
    DATES: dateLabels(),
    TODAY_IDX: idx,
    FRESHNESS: freshnessFromResp(resp.freshness),
    MEMBERS: members,
    TEAM: {
      teamName: resp.teamName || resp.team || '',
      leadName: resp.leadName || '',
      memberCount: resp.memberCount || members.length,
      totalResources: resp.totalResources || 0,
      teamPace: resp.teamPace || 0,
      expectedPace: resp.expectedPace || 0,
      benchmarkPace: resp.benchmarkPace || resp.expectedPace || 0,
      members,
    },
    BY_SEVERITY: resp.bySeverity || { critical: [], high: [], watch: [], ok: [], leave: [] },
    LEADERBOARD: resp.leaderboard || [],
    ACTION_LOG: resp.actionLog || [],
    PACE_TREND: pacePlaceholder(resp.teamPace || 0),
    PL_TEAMS: [], // populated by getPLTrackingData when the PL tab loads
    TODAY_BUCKETS: buildTodayBuckets(members, idx),
    SEV_META,
    weekLabel: resp.weekLabel || 'This Week',
    weekOffset: resp.weekOffset ?? 0,
    isPastWeek: resp.isPastWeek || false,
    loadTime: resp.loadTime,
    viewerRole: resp.viewerRole,
  };
}

// React hook used by every tab. Loads getTeamData on first call, exposes
// `data, loading, error, refresh, setWeekOffset`. Auto-refreshes every
// REFRESH_MS while the browser tab is visible — pauses when hidden so we
// don't spend Firestore reads on an idle tab. Cadence aligns with the
// slowest backend source (KPI every 60 min) so we're not pulling more
// often than data actually changes; manual Refresh button in the sidebar
// covers the "I want it now" case.
//
// `teamOverride` (admin-only) — when set, the hook calls getTeamDataAdmin
// with that team name instead of getTeamData. Lets a company admin pivot
// the entire team-lead-style dashboard (Overview / Clock-in / Performance
// / Roster / Action log) to any project. Backend enforces admin role on
// getTeamDataAdmin, so leads passing a string here would just get a
// permission-denied — the UI gate keeps the picker out of their reach.
// Auto-refresh cadence. 20 min is roughly the slowest backend source's
// freshness (KPI ingest tick is 60 min; Quidlo ingest ~5 min). Doubling
// from the original 10 min cuts dashboard read volume in half while
// still feeling "live" — the manual Refresh button covers the "I want
// it now" case. Each open tab still ticks independently, so multi-tab
// users pay multi-tab cost.
const REFRESH_MS = 20 * 60 * 1000; // 20 min

function useTeamData(initialOffset, teamOverride) {
  const [state, setState] = dlUseState({ data: null, loading: true, error: null });
  const [weekOffset, setWeekOffset] = dlUseState(initialOffset || 0);
  const [lastLoadedAt, setLastLoadedAt] = dlUseState(null);

  const load = dlUseCallback(function (off, override) {
    setState((s) => Object.assign({}, s, { loading: true, error: null }));
    const fn = override ? 'getTeamDataAdmin' : 'getTeamData';
    const args = override ? { team: override, weekOffset: off } : { weekOffset: off };
    window.YDApp.call(fn, args)
      .then(function (resp) {
        populateWindowYD(resp);
        setState({ data: resp, loading: false, error: null });
        setLastLoadedAt(Date.now());
      })
      .catch(function (err) {
        console.error(fn + ' failed', err);
        setState({ data: null, loading: false, error: err.message || String(err) });
      });
  }, []);

  dlUseEffect(function () { load(weekOffset, teamOverride); }, [load, weekOffset, teamOverride]);

  // Auto-refresh on a 3-minute tick, pausing while the tab isn't visible.
  // visibilitychange + a setInterval keeps the budget sane on free tier
  // (~20 refreshes/hr active vs 96 if we ignored visibility).
  dlUseEffect(function () {
    let timer = null;
    const tick = () => { if (document.visibilityState === 'visible') load(weekOffset, teamOverride); };
    timer = setInterval(tick, REFRESH_MS);
    const onVis = () => {
      // Refresh once immediately if the user comes back after being away
      // long enough that data is likely stale.
      if (document.visibilityState === 'visible' && lastLoadedAt && Date.now() - lastLoadedAt > REFRESH_MS) {
        load(weekOffset, teamOverride);
      }
    };
    document.addEventListener('visibilitychange', onVis);
    return () => {
      if (timer) clearInterval(timer);
      document.removeEventListener('visibilitychange', onVis);
    };
  }, [load, weekOffset, teamOverride, lastLoadedAt]);

  return Object.assign({}, state, {
    weekOffset,
    setWeekOffset,
    lastLoadedAt,
    refresh: function () { load(weekOffset, teamOverride); },
  });
}

window.YDLoader = { populateWindowYD, useTeamData, SEV_META };
