// =========================================================
// FILE: dashboard.js | TYPE: Dashboard Logic
// =========================================================

import { db } from "./firebase-config.js";
import { requireAuth, setupLogoutButton } from "./app-guard.js";
import { showLoader, hideLoader } from "./loader.js";
import { showToast } from "./toast.js";
import { createNotification } from "./notification-service.js";

import {
  collection,
  getDocs,
  getDoc,
  query,
  where,
  doc,
  updateDoc,
  serverTimestamp
} from "https://www.gstatic.com/firebasejs/10.12.2/firebase-firestore.js";

// ── Security: escape HTML to prevent XSS when inserting Firestore data ──
function escHtml(str) {
  if (str === null || str === undefined) return "";
  return String(str)
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;");
}


const elements = {
  totalPlayers: document.getElementById("totalPlayers"),
  totalTeams: document.getElementById("totalTeams"),
  dashboardReadyPlayers: document.getElementById("dashboardReadyPlayers"),
  dashboardMonitorPlayers: document.getElementById("dashboardMonitorPlayers"),
  dashboardWellnessScore: document.getElementById("dashboardWellnessScore"),
  dashboardAttendanceScore: document.getElementById("dashboardAttendanceScore"),
  injuryCount: document.getElementById("injuryCount"),
  recentActivityList: document.getElementById("recentActivityList"),
  dashboardTrainingLoad: document.getElementById("dashboardTrainingLoad"),
  dashboardLoadRisk: document.getElementById("dashboardLoadRisk"),
  
  dashboardSubscriptionPlan: document.getElementById("dashboardSubscriptionPlan"),
  dashboardSubscriptionStatus: document.getElementById("dashboardSubscriptionStatus"),
  dashboardSubscriptionTrend: document.getElementById("dashboardSubscriptionTrend"),

  readyTrend: document.getElementById("readyTrend"),
  monitorTrend: document.getElementById("monitorTrend"),
  injuryTrend: document.getElementById("injuryTrend"),
  wellnessTrend: document.getElementById("wellnessTrend"),
  attendanceTrend: document.getElementById("attendanceTrend"),
  trainingLoadTrend: document.getElementById("trainingLoadTrend"),
  loadRiskTrend: document.getElementById("loadRiskTrend"),

  riskCategoryChart: document.getElementById("riskCategoryChart"),
  wellnessChart: document.getElementById("wellnessChart"),
  trainingLoadChart: document.getElementById("trainingLoadChart"),
  weeklyAttendanceChart: document.getElementById("weeklyAttendanceChart"),
  weeklyPerformanceChart: document.getElementById("weeklyPerformanceChart"),
  weeklyWellnessChart: document.getElementById("weeklyWellnessChart"),
  teamComparisonChart: document.getElementById("teamComparisonChart"),
  directorComparisonSection: document.getElementById("directorComparisonSection"),
  teamComparisonTable: document.getElementById("teamComparisonTable"),
  directorRiskInsights: document.getElementById("directorRiskInsights"),
  playerRiskLeaderboard: document.getElementById("playerRiskLeaderboard"),

  squadAvailability: document.getElementById("squadAvailability"),
  averageWellness: document.getElementById("averageWellness"),
  attendanceRate: document.getElementById("attendanceRate"),
  loadStatus: document.getElementById("loadStatus"),

  dashboardGreeting: document.getElementById("dashboardGreeting"),
  dashboardViewLabel: document.getElementById("dashboardViewLabel"),
  dashboardInsights: document.getElementById("dashboardInsights"),
  dashboardNotificationsList: document.getElementById("dashboardNotificationsList"),

  heroSquadReady: document.getElementById("heroSquadReady"),
  heroRiskLevel: document.getElementById("heroRiskLevel"),
  heroLoadStatus: document.getElementById("heroLoadStatus"),
  heroFocusTitle: document.getElementById("heroFocusTitle"),
  heroFocusText: document.getElementById("heroFocusText")
};

let riskCategoryChartInstance = null;
let wellnessChartInstance = null;
let trainingLoadChartInstance = null;
let weeklyAttendanceChartInstance = null;
let weeklyPerformanceChartInstance = null;
let weeklyWellnessChartInstance = null;
let teamComparisonChartInstance = null;
let activeProfile = null;
let dashboardNotificationRecords = [];
let dashboardRefreshIsRunning = false;

const CHART_THEME = {
  ready: "rgba(34,197,94,0.85)",
  warning: "rgba(245,158,11,0.85)",
  danger: "rgba(239,68,68,0.85)",
  primary: "rgba(56,189,248,0.85)",
  primarySoft: "rgba(56,189,248,0.16)",
  text: "#ffffff",
  muted: "#cbd5e1",
  surface: "#0f172a",
  grid: "rgba(255,255,255,0.06)"
};

function safeText(value, fallback = "") {
  if (value === null || value === undefined || value === "") return fallback;
  return String(value);
}

function setText(element, value) {
  if (!element) return;
  element.textContent = value;
}

function isNotificationRead(notification) {
  if (!notification || !activeProfile?.uid) return false;

  return Boolean(
    notification.readBy &&
    notification.readBy[activeProfile.uid]
  );
}

function getReadByUpdate() {
  return {
    [`readBy.${activeProfile.uid}`]: true
  };
}

async function getCollectionRecords(collectionName) {
  if (!activeProfile?.organisationId) return [];

  const q = query(
    collection(db, collectionName),
    where("organisationId", "==", activeProfile.organisationId)
  );

  const snapshot = await getDocs(q);

  return snapshot.docs.map((docSnap) => ({
    id: docSnap.id,
    ...docSnap.data()
  }));
}

function canAccessPlayer(player) {
  if (!activeProfile || !player) return false;

  const role = activeProfile.role;
  const assignedTeamIds = activeProfile.assignedTeamIds || [];
  const assignedPlayerIds = activeProfile.assignedPlayerIds || [];
  const playerTeamIds = getPlayerTeamIds(player);

  if (role === "director") return true;

  if (role === "coach") {
    return playerTeamIds.some((teamId) => assignedTeamIds.includes(teamId));
  }

  if (role === "biokineticist") {
    return (
      playerTeamIds.some((teamId) => assignedTeamIds.includes(teamId)) ||
      assignedPlayerIds.includes(player.id)
    );
  }

  if (role === "player") {
    return (
      player.userId === activeProfile.uid ||
      player.id === activeProfile.playerId ||
      assignedPlayerIds.includes(player.id)
    );
  }

  return false;
}

function getPlayerTeamIds(player) {
  const teamIds = Array.isArray(player?.teamIds)
    ? [...player.teamIds]
    : [];

  if (player?.teamId && !teamIds.includes(player.teamId)) {
    teamIds.push(player.teamId);
  }

  return teamIds.filter(Boolean);
}

function getDateValue(record) {
  const dateValue =
    record?.date ||
    record?.sessionDate ||
    record?.createdDate;

  if (dateValue) {
    const dateString = String(dateValue);

    if (/^\d{4}-\d{2}-\d{2}$/.test(dateString)) {
      const [year, month, day] = dateString.split("-").map(Number);
      return new Date(year, month - 1, day);
    }

    return new Date(dateValue);
  }

  if (record?.createdAt?.toDate) return record.createdAt.toDate();
  if (record?.createdAt) return new Date(record.createdAt);

  return new Date(0);
}

function getDashboardLoadRisk(averageLoad) {
  if (averageLoad >= 500) return "Overload";
  if (averageLoad >= 350) return "High";
  if (averageLoad >= 180) return "Optimal";
  if (averageLoad > 0) return "Low";
  return "No Data";
}

function calculateWellnessScore(record) {
  if (!record) return 0;

  const sleep = Number(record.sleep || 0);
  const fatigue = Number(record.fatigue || 0);
  const soreness = Number(record.soreness || 0);

  const reverseFatigue = Math.max(0, 6 - fatigue);
  const reverseSoreness = Math.max(0, 6 - soreness);

  const total = sleep + reverseFatigue + reverseSoreness;

  return Math.round((total / 15) * 100);
}

function isActiveInjury(injury) {
  const status = String(injury.status || "").toLowerCase();
  return status !== "cleared" && status !== "closed" && status !== "resolved";
}

function groupByPlayerId(records) {
  const map = new Map();

  records.forEach((record) => {
    if (!record.playerId) return;

    if (!map.has(record.playerId)) {
      map.set(record.playerId, []);
    }

    map.get(record.playerId).push(record);
  });

  return map;
}

function getLatestByPlayerId(records) {
  const map = new Map();

  records.forEach((record) => {
    if (!record.playerId) return;

    const existing = map.get(record.playerId);

    if (!existing || getDateValue(record) > getDateValue(existing)) {
      map.set(record.playerId, record);
    }
  });

  return map;
}

function updateTrendElement(element, text, trendClass) {
  if (!element) return;

  element.textContent = text;
  element.className = `stat-trend ${trendClass}`;
}

function updateEliteHero({
  squadAvailabilityPercentage,
  activeInjuryCount,
  lowWellnessCount,
  lowAttendanceCount,
  averageTrainingLoad
}) {
  const loadRisk = getDashboardLoadRisk(averageTrainingLoad);

  setText(elements.heroSquadReady, `${squadAvailabilityPercentage}%`);
  setText(elements.heroLoadStatus, loadRisk);

  let riskLevel = "Low";
  let focusTitle = "Squad trending well";
  let focusText = "Readiness, attendance and wellness are currently within a healthy operating range.";

  if (activeInjuryCount > 0 || averageTrainingLoad >= 500) {
    riskLevel = "High";
    focusTitle = "Protect player availability";
    focusText = "Injury risk or training overload requires immediate staff review before selection.";
  } else if (lowWellnessCount > 0 || lowAttendanceCount > 0 || averageTrainingLoad >= 350) {
    riskLevel = "Moderate";
    focusTitle = "Monitor readiness signals";
    focusText = "Some players show wellness, attendance or training load signals that need coach attention.";
  }

  setText(elements.heroRiskLevel, riskLevel);
  setText(elements.heroFocusTitle, focusTitle);
  setText(elements.heroFocusText, focusText);
}

function getBaseChartOptions(extraOptions = {}) {
  return {
    responsive: true,
    maintainAspectRatio: false,
    animation: {
      duration: 900,
      easing: "easeOutQuart"
    },
    plugins: {
      tooltip: {
        backgroundColor: CHART_THEME.surface,
        borderColor: "rgba(56,189,248,0.25)",
        borderWidth: 1,
        titleColor: CHART_THEME.text,
        bodyColor: CHART_THEME.muted,
        padding: 14,
        displayColors: true
      }
    },
    ...extraOptions
  };
}

function renderRiskCategoryChart({
  lowWellnessCount,
  lowAttendanceCount,
  activeInjuryCount,
  missingWellness,
  averageTrainingLoad
}) {
  if (!elements.riskCategoryChart || typeof Chart === "undefined") return;

  if (riskCategoryChartInstance) {
    riskCategoryChartInstance.destroy();
  }

  const overloadCount = averageTrainingLoad >= 500 ? 1 : 0;

  riskCategoryChartInstance = new Chart(elements.riskCategoryChart, {
    type: "bar",
    data: {
      labels: ["Low Wellness", "Low Attendance", "Active Injuries", "High Load", "Missing Wellness"],
      datasets: [
        {
          label: "Risk Count",
          data: [
            lowWellnessCount,
            lowAttendanceCount,
            activeInjuryCount,
            overloadCount,
            missingWellness
          ],
          backgroundColor: [
            CHART_THEME.danger,
            CHART_THEME.warning,
            CHART_THEME.danger,
            "rgba(168,85,247,0.85)",
            "rgba(148,163,184,0.85)"
          ],
          borderRadius: 14
        }
      ]
    },
    options: getBaseChartOptions({
      plugins: {
        legend: { display: false },
        tooltip: getBaseChartOptions().plugins.tooltip
      },
      scales: {
        y: {
          beginAtZero: true,
          ticks: {
            color: CHART_THEME.muted,
            precision: 0
          },
          grid: { color: CHART_THEME.grid }
        },
        x: {
          ticks: { color: CHART_THEME.text },
          grid: { display: false }
        }
      }
    })
  });
}

function renderWellnessChart(goodCount, moderateCount, poorCount, missingCount = 0) {
  if (!elements.wellnessChart || typeof Chart === "undefined") return;

  const total = goodCount + moderateCount + poorCount + missingCount;

  if (!total) {
    goodCount = 0;
    moderateCount = 0;
    poorCount = 0;
    missingCount = 1;
  }

  if (wellnessChartInstance) {
    wellnessChartInstance.destroy();
  }

  wellnessChartInstance = new Chart(elements.wellnessChart, {
    type: "bar",
    data: {
      labels: ["Good", "Moderate", "Poor", "Missing"],
      datasets: [
        {
          label: "Players",
          data: [goodCount, moderateCount, poorCount, missingCount],
          backgroundColor: [
            CHART_THEME.ready,
            CHART_THEME.warning,
            CHART_THEME.danger,
            "rgba(148,163,184,0.75)"
          ],
          borderRadius: 14
        }
      ]
    },
    options: getBaseChartOptions({
      plugins: {
        legend: { display: false },
        tooltip: getBaseChartOptions().plugins.tooltip
      },
      scales: {
        y: {
          beginAtZero: true,
          ticks: {
            color: CHART_THEME.muted,
            precision: 0
          },
          grid: { color: CHART_THEME.grid }
        },
        x: {
          ticks: { color: CHART_THEME.text },
          grid: { display: false }
        }
      }
    })
  });
}

function renderTrainingLoadChart(trainingSessions) {
  if (!elements.trainingLoadChart || typeof Chart === "undefined") return;

  if (trainingLoadChartInstance) {
    trainingLoadChartInstance.destroy();
  }

  const sortedSessions = [...trainingSessions]
    .sort((a, b) => getDateValue(a) - getDateValue(b))
    .slice(-7);

  let labels = sortedSessions.map((session) => {
    if (!session.date) return "Session";

    const date = new Date(session.date);
    return `${date.getDate()}/${date.getMonth() + 1}`;
  });

  let loads = sortedSessions.map((session) => Number(session.sessionLoad || 0));

  if (!loads.length) {
    labels = ["No Data"];
    loads = [0];
  }

  trainingLoadChartInstance = new Chart(elements.trainingLoadChart, {
    type: "line",
    data: {
      labels,
      datasets: [
        {
          label: "Training Load",
          data: loads,
          borderColor: "#38bdf8",
          backgroundColor: CHART_THEME.primarySoft,
          fill: true,
          tension: 0.35,
          pointRadius: 5,
          pointHoverRadius: 7,
          pointBackgroundColor: "#38bdf8"
        }
      ]
    },
    options: getBaseChartOptions({
      plugins: {
        legend: { display: false },
        tooltip: getBaseChartOptions().plugins.tooltip
      },
      scales: {
        y: {
          beginAtZero: true,
          ticks: { color: CHART_THEME.muted },
          grid: { color: CHART_THEME.grid }
        },
        x: {
          ticks: { color: CHART_THEME.text },
          grid: { display: false }
        }
      }
    })
  });
}

function updateStatusValue(element, text, className) {
  if (!element) return;

  element.textContent = text;
  element.classList.remove("status-good", "status-watch", "status-risk");
  element.classList.add(className);
}

function updateDashboardGreeting(profile) {
  if (!elements.dashboardGreeting) return;

  const currentHour = new Date().getHours();

  let greeting = "Welcome";

  if (currentHour < 12) {
    greeting = "Good Morning";
  } else if (currentHour < 18) {
    greeting = "Good Afternoon";
  } else {
    greeting = "Good Evening";
  }

  const firstName = profile.fullName ? profile.fullName.split(" ")[0] : "Coach";

  elements.dashboardGreeting.textContent = `${greeting}, ${firstName}`;
}

function updateDashboardViewLabel(profile) {
  if (!elements.dashboardViewLabel) return;

  if (profile.role === "director") {
    elements.dashboardViewLabel.textContent =
      "Director View • Organisation Dashboard";

  } else if (profile.role === "coach") {
    elements.dashboardViewLabel.textContent =
      "Coach View • Team Dashboard";

  } else if (profile.role === "biokineticist") {
    elements.dashboardViewLabel.textContent =
      "Biokineticist View • Player Health Dashboard";

  } else {
    elements.dashboardViewLabel.textContent =
      "Player View • Personal Dashboard";
  }
}

function renderDashboardInsights({
  squadAvailabilityPercentage,
  averageWellnessPercentage,
  attendanceRatePercentage,
  activeInjuryCount,
  averageTrainingLoad
}) {
  if (!elements.dashboardInsights) return;

  const insights = [];

  if (squadAvailabilityPercentage >= 80) {
    insights.push({
      type: "good",
      title: "Squad Availability Stable",
      text: `${squadAvailabilityPercentage}% of the squad is currently ready.`
    });
  } else {
    insights.push({
      type: "warning",
      title: "Squad Availability Needs Review",
      text: `Only ${squadAvailabilityPercentage}% of the squad is currently ready.`
    });
  }

  if (averageWellnessPercentage < 50) {
    insights.push({
      type: "danger",
      title: "Wellness Risk Detected",
      text: `Average wellness is low at ${averageWellnessPercentage}%.`
    });
  } else if (averageWellnessPercentage < 70) {
    insights.push({
      type: "warning",
      title: "Wellness Monitoring Active",
      text: `Average wellness is currently ${averageWellnessPercentage}%.`
    });
  } else {
    insights.push({
      type: "good",
      title: "Wellness Level Healthy",
      text: `Average wellness is currently ${averageWellnessPercentage}%.`
    });
  }

  if (activeInjuryCount > 0) {
    insights.push({
      type: "danger",
      title: "Injury Risks Identified",
      text: `${activeInjuryCount} active injury risk(s) require review.`
    });
  }

  if (attendanceRatePercentage < 65) {
    insights.push({
      type: "warning",
      title: "Attendance Concern",
      text: `Attendance rate is currently ${attendanceRatePercentage}%.`
    });
  }

  if (averageTrainingLoad >= 500) {
    insights.push({
      type: "danger",
      title: "Training Overload Risk",
      text: `Average training load is ${averageTrainingLoad}. Recovery planning is recommended.`
    });
  } else if (averageTrainingLoad >= 350) {
    insights.push({
      type: "warning",
      title: "High Training Load",
      text: `Average training load is ${averageTrainingLoad}. Monitor fatigue.`
    });
  }

  if (!insights.length) {
    insights.push({
      type: "good",
      title: "No Major Alerts",
      text: "The dashboard is currently showing a stable team profile."
    });
  }

  elements.dashboardInsights.innerHTML = "";

  insights.slice(0, 4).forEach((insight) => {
    const item = document.createElement("div");
    item.className = "insight-item";

    item.innerHTML = `
      <span class="insight-dot insight-${insight.type}"></span>
      <div>
        <strong>${insight.title}</strong>
        <p>${insight.text}</p>
      </div>
    `;

    elements.dashboardInsights.appendChild(item);
  });
}

function animateCounter(element, targetValue, duration = 750) {
  if (!element) return;

  const startValue = Number(element.textContent) || 0;
  const startTime = performance.now();

  function updateCounter(currentTime) {
    const elapsed = currentTime - startTime;
    const progress = Math.min(elapsed / duration, 1);
    const currentValue = Math.floor(progress * (targetValue - startValue) + startValue);

    element.textContent = currentValue;

    if (progress < 1) {
      requestAnimationFrame(updateCounter);
    } else {
      element.textContent = targetValue;
    }
  }

  requestAnimationFrame(updateCounter);
}

function updateLoadRiskCard(averageTrainingLoad) {
  const loadRiskCard = elements.dashboardLoadRisk?.closest(".premium-stat-card");

  if (!loadRiskCard) return;

  loadRiskCard.classList.remove("stat-ready", "stat-warning", "stat-danger", "stat-monitor");

  if (averageTrainingLoad >= 500) {
    loadRiskCard.classList.add("stat-danger");
  } else if (averageTrainingLoad >= 350) {
    loadRiskCard.classList.add("stat-warning");
  } else if (averageTrainingLoad > 0) {
    loadRiskCard.classList.add("stat-ready");
  } else {
    loadRiskCard.classList.add("stat-monitor");
  }
}

function hasCoachAssignments() {
  const assignedTeamIds = activeProfile?.assignedTeamIds || [];
  return assignedTeamIds.length > 0;
}

function renderRecentActivity(attendance, wellness, injuries, trainingSessions) {
  if (!elements.recentActivityList) return;

  const activities = [
    ...attendance.map((record) => ({
      type: "Attendance",
      title: safeText(record.playerName, "Unknown Player"),
      detail: `${safeText(record.teamName, "No team")} • ${safeText(record.status, "No status")} • ${safeText(record.date || record.sessionDate || record.createdDate, "No date")}`,
      date: getDateValue(record)
    })),

    ...wellness.map((record) => ({
      type: "Wellness",
      title: safeText(record.playerName, "Unknown Player"),
      detail: `${safeText(record.teamName, "No team")} • Sleep ${safeText(record.sleep, "-")}/5 • Energy ${safeText(record.energy, "-")}/5 • Soreness ${safeText(record.soreness, "-")}/5`,
      date: getDateValue(record)
    })),

    ...injuries.map((record) => ({
      type: "Injury",
      title: safeText(record.playerName, "Unknown Player"),
      detail: `${safeText(record.teamName, "No team")} • ${safeText(record.type || record.injuryType, "No type")} • ${safeText(record.status, "No status")}`,
      date: getDateValue(record)
    })),

    ...trainingSessions.map((session) => ({
      type: "Training",
      title: safeText(session.teamName, "Training Session"),
      detail: `${safeText(session.date, "No date")} • Load ${safeText(session.sessionLoad, 0)} • ${safeText(session.type, "training")}`,
      date: getDateValue(session)
    }))
  ];

  activities.sort((a, b) => b.date - a.date);

  const latest = activities.slice(0, 8);

  elements.recentActivityList.innerHTML = "";

  if (!latest.length) {
    elements.recentActivityList.innerHTML = `<div class="app-card">No recent activity yet.</div>`;
    return;
  }

  latest.forEach((activity) => {
    const item = document.createElement("a");
    item.className = "recent-activity-item";

    item.href =
      activity.type === "Injury"
        ? "injuries.html"
        : activity.type === "Wellness"
          ? "wellness.html"
          : activity.type === "Training"
            ? "training.html"
            : "attendance.html";

    item.innerHTML = `
      <div>
        <span class="activity-type">${activity.type}</span>
        <h3>${activity.title}</h3>
        <p>${activity.detail}</p>
      </div>
    `;

    elements.recentActivityList.appendChild(item);
  });
}

async function loadDashboardNotifications() {
  if (!elements.dashboardNotificationsList || !activeProfile?.organisationId) return;

  const notificationsQuery = query(
    collection(db, "notifications"),
    where("organisationId", "==", activeProfile.organisationId),
    where("userId", "==", activeProfile.uid)
  );

  const snapshot = await getDocs(notificationsQuery);

  dashboardNotificationRecords = snapshot.docs
    .map((docSnap) => ({
      id: docSnap.id,
      ...docSnap.data()
    }))
    .sort((a, b) => getDateValue(b) - getDateValue(a));

  renderDashboardNotifications();
}

function renderDashboardNotifications() {
  if (!elements.dashboardNotificationsList) return;

  elements.dashboardNotificationsList.innerHTML = "";

  if (!dashboardNotificationRecords.length) {
    elements.dashboardNotificationsList.innerHTML = `<div class="app-card">No notifications yet.</div>`;
    return;
  }

  dashboardNotificationRecords.slice(0, 6).forEach((notification) => {
    const item = document.createElement("div");
    item.className = `app-card notification-${notification.severity || "info"}`;

    item.innerHTML = `
      <strong>${notification.title || "Notification"}</strong>
      <small>${notification.message || ""}</small>

      <div class="record-actions">
        ${notification.link ? `<a href="${notification.link}" class="btn-secondary">Open</a>` : ""}
        ${
          isNotificationRead(notification)
            ? `<span class="status-pill">Read</span>`
            : `<button class="btn-primary dashboard-mark-notification-read-btn" data-id="${notification.id}">
                Mark Read
              </button>`
        }
      </div>
    `;

    elements.dashboardNotificationsList.appendChild(item);
  });
}

function setupDashboardNotificationActions() {
  document.querySelectorAll(".dashboard-mark-notification-read-btn").forEach((button) => {
    button.addEventListener("click", async () => {
      const notificationId = button.dataset.id;

      if (!notificationId) return;

      button.disabled = true;
      button.textContent = "Updating...";

      try {
        await updateDoc(doc(db, "notifications", notificationId), {
          ...getReadByUpdate(),
          updatedAt: serverTimestamp()
        });

        showToast("Notification marked as read", "success");

        const notification = dashboardNotificationRecords.find((item) => item.id === notificationId);

        if (notification) {
          notification.readBy = {
            ...(notification.readBy || {}),
            [activeProfile.uid]: true
        };
        }

        renderDashboardNotifications();
        setupDashboardNotificationActions();
      } catch (error) {
        console.error("Dashboard notification update error:", error);
        showToast("Could not update notification", "error");
      } finally {
        button.disabled = false;
      }
    });
  });
}

async function createDashboardRiskNotifications({
  activeInjuryCount,
  lowWellnessCount,
  lowAttendanceCount,
  averageTrainingLoad
}) {
  if (!activeProfile?.uid || !activeProfile?.organisationId) return;

  const notificationJobs = [];

  if (activeInjuryCount > 0) {
    notificationJobs.push(
      createNotification({
        organisationId: activeProfile.organisationId,
        userId: activeProfile.uid,
        type: "dashboard_alert",
        title: "Active injury risks",
        message: `${activeInjuryCount} player(s) currently have active injury records.`,
        link: "injuries.html",
        severity: "danger",
        uniqueKey: `dashboard-injuries-${activeProfile.uid}`
      })
    );
  }

  if (lowWellnessCount > 0) {
    notificationJobs.push(
      createNotification({
        organisationId: activeProfile.organisationId,
        userId: activeProfile.uid,
        type: "dashboard_alert",
        title: "Low wellness detected",
        message: `${lowWellnessCount} player(s) are below the wellness threshold.`,
        link: "wellness.html",
        severity: "warning",
        uniqueKey: `dashboard-low-wellness-${activeProfile.uid}`
      })
    );
  }

  if (lowAttendanceCount > 0) {
    notificationJobs.push(
      createNotification({
        organisationId: activeProfile.organisationId,
        userId: activeProfile.uid,
        type: "dashboard_alert",
        title: "Low attendance detected",
        message: `${lowAttendanceCount} player(s) are below the attendance threshold.`,
        link: "attendance.html",
        severity: "warning",
        uniqueKey: `dashboard-low-attendance-${activeProfile.uid}`
      })
    );
  }

  if (averageTrainingLoad >= 500) {
    notificationJobs.push(
      createNotification({
        organisationId: activeProfile.organisationId,
        userId: activeProfile.uid,
        type: "dashboard_alert",
        title: "Training overload risk",
        message: `Average training load is ${averageTrainingLoad}. Recovery planning is recommended.`,
        link: "training.html",
        severity: "danger",
        uniqueKey: `dashboard-training-overload-${activeProfile.uid}`
      })
    );
  }

  await Promise.allSettled(notificationJobs);
}

function renderNoTeamAssignedState() {
  animateCounter(elements.totalPlayers, 0);
  animateCounter(elements.dashboardReadyPlayers, 0);
  animateCounter(elements.dashboardMonitorPlayers, 0);
  setText(elements.dashboardWellnessScore, "0%");
  
  const wellnessRing = document.querySelector(".premium-wellness-ring");

  if (wellnessRing) {
    wellnessRing.style.setProperty("--value", "0%");
  }

  setText(elements.dashboardAttendanceScore, "0%");
  animatePremiumRing(".premium-attendance-ring", 0);
  animateCounter(elements.injuryCount, 0);
  animateCounter(elements.dashboardTrainingLoad, 0);

  setText(elements.dashboardLoadRisk, "No Team");

  updateEliteHero({
    squadAvailabilityPercentage: 0,
    activeInjuryCount: 0,
    lowWellnessCount: 0,
    lowAttendanceCount: 0,
    averageTrainingLoad: 0
  });

  setText(elements.heroRiskLevel, "No Team");
  setText(elements.heroFocusTitle, "No team assigned");
  setText(elements.heroFocusText, "This coach does not have access to any team yet. Ask the director to assign a team in User Management.");

  updateTrendElement(elements.readyTrend, "No team assigned", "trend-warning");
  updateTrendElement(elements.monitorTrend, "No team assigned", "trend-warning");
  updateTrendElement(elements.injuryTrend, "No team assigned", "trend-warning");
  updateTrendElement(elements.wellnessTrend, "No team assigned", "trend-warning");
  updateTrendElement(elements.attendanceTrend, "No team assigned", "trend-warning");
  updateTrendElement(elements.trainingLoadTrend, "No team assigned", "trend-warning");
  updateTrendElement(elements.loadRiskTrend, "Assign coach to a team", "trend-warning");

  updateStatusValue(elements.squadAvailability, "0%", "status-watch");
  updateStatusValue(elements.averageWellness, "0%", "status-watch");
  updateStatusValue(elements.attendanceRate, "0%", "status-watch");
  updateStatusValue(elements.loadStatus, "No Team", "status-watch");

  if (elements.recentActivityList) {
    elements.recentActivityList.innerHTML = `
      <div class="app-card">
        No team assigned yet. Please ask the director to assign this coach to a team in User Management.
      </div>
    `;
  }

  if (elements.dashboardInsights) {
    elements.dashboardInsights.innerHTML = `
      <div class="insight-item">
        <span class="insight-dot insight-warning"></span>
        <div>
          <strong>No Team Assigned</strong>
          <p>This coach does not have access to any team yet.</p>
        </div>
      </div>
    `;
  }

  renderRiskCategoryChart({
    lowWellnessCount: 0,
    lowAttendanceCount: 0,
    activeInjuryCount: 0,
    missingWellness: 0,
    averageTrainingLoad: 0
  });
}

async function loadDashboardSubscription() {
  if (!activeProfile?.organisationId) return;

  try {
    const organisationRef = doc(db, "organisations", activeProfile.organisationId);
    const organisationSnap = await getDoc(organisationRef);

    if (!organisationSnap.exists()) {
      setText(elements.dashboardSubscriptionPlan, "Unknown");
      setText(elements.dashboardSubscriptionStatus, "Organisation not found");
      updateTrendElement(elements.dashboardSubscriptionTrend, "Check organisation setup", "trend-warning");
      return;
    }

    const organisation = organisationSnap.data();
    const subscription = organisation.subscription || {};

    const plan = subscription.plan || "trial";
const status = subscription.status || "trial";
const isDemo = subscription.isDemo === true || status === "demo";

setText(
  elements.dashboardSubscriptionPlan,
  plan.charAt(0).toUpperCase() + plan.slice(1)
);

  if (isDemo) {
    setText(elements.dashboardSubscriptionStatus, "Demo organisation active");
    updateTrendElement(elements.dashboardSubscriptionTrend, "Demo active", "trend-up");
  } else if (status === "trial") {
    setText(elements.dashboardSubscriptionStatus, "Trial subscription active");
    updateTrendElement(elements.dashboardSubscriptionTrend, "Trial mode", "trend-warning");
  } else if (status === "active") {
    setText(elements.dashboardSubscriptionStatus, "Subscription active");
    updateTrendElement(elements.dashboardSubscriptionTrend, "Account in good standing", "trend-up");
  } else {
    setText(elements.dashboardSubscriptionStatus, "Subscription inactive");
    updateTrendElement(elements.dashboardSubscriptionTrend, "Upgrade required", "trend-danger");
  }
  } catch (error) {
    console.error("Dashboard subscription error:", error);
    setText(elements.dashboardSubscriptionPlan, "Error");
    setText(elements.dashboardSubscriptionStatus, "Could not load subscription");
    updateTrendElement(elements.dashboardSubscriptionTrend, "Subscription check failed", "trend-danger");
  }
}

function animatePremiumRing(selector, percentage) {
  const ring = document.querySelector(selector);

  if (!ring) return;

  ring.classList.add("is-loading");
  ring.classList.remove("is-loaded");

  ring.style.setProperty("--value", "0%");

  requestAnimationFrame(() => {
    setTimeout(() => {
      ring.style.setProperty("--value", `${percentage}%`);
      ring.classList.remove("is-loading");
      ring.classList.add("is-loaded");
    }, 180);
  });
}

function renderTeamComparisonChart(teamStats) {
  if (!elements.teamComparisonChart || typeof Chart === "undefined") return;

  if (teamComparisonChartInstance) {
    teamComparisonChartInstance.destroy();
  }

  const sortedTeams = [...teamStats].sort((a, b) => b.readiness - a.readiness);

  teamComparisonChartInstance = new Chart(elements.teamComparisonChart, {
    type: "bar",
    data: {
      labels: sortedTeams.map((team) => team.name),
      datasets: [
        {
          label: "Readiness %",
          data: sortedTeams.map((team) => team.readiness),
          backgroundColor: CHART_THEME.ready,
          borderRadius: 12
        },
        {
          label: "Wellness %",
          data: sortedTeams.map((team) => team.wellness),
          backgroundColor: CHART_THEME.primary,
          borderRadius: 12
        },
        {
          label: "Attendance %",
          data: sortedTeams.map((team) => team.attendance),
          backgroundColor: CHART_THEME.warning,
          borderRadius: 12
        }
      ]
    },
    options: getBaseChartOptions({
      plugins: {
        tooltip: getBaseChartOptions().plugins.tooltip,
        legend: {
          position: "bottom",
          labels: {
            color: CHART_THEME.text,
            padding: 16,
            boxWidth: 14,
            boxHeight: 14,
            font: {
              size: 11,
              weight: "700"
            }
          }
        }
      },
      scales: {
        y: {
          beginAtZero: true,
          max: 100,
          ticks: {
            color: CHART_THEME.muted,
            callback: (value) => `${value}%`
          },
          grid: { color: CHART_THEME.grid }
        },
        x: {
          ticks: { color: CHART_THEME.text },
          grid: { display: false }
        }
      }
    })
  });
}

function renderTeamComparisonTable(teamStats) {
  if (!elements.teamComparisonTable) return;

  if (!teamStats.length) {
    elements.teamComparisonTable.innerHTML = `
      <div class="app-card">No team comparison data available yet.</div>
    `;
    return;
  }

  const sortedTeams = [...teamStats].sort((a, b) => b.readiness - a.readiness);

  elements.teamComparisonTable.innerHTML = `
    <div class="comparison-table-header">
      <span>Team</span>
      <span>Ready</span>
      <span>Wellness</span>
      <span>Attendance</span>
      <span>Injuries</span>
      <span>Risk</span>
    </div>

    ${sortedTeams.map((team) => `
      <div class="comparison-table-row">
        <strong>${team.name}</strong>
        <span>${team.readiness}%</span>
        <span>${team.wellness}%</span>
        <span>${team.attendance}%</span>
        <span>${team.injuries}</span>
        <span class="risk-pill risk-${team.riskClass}">${team.risk}</span>
      </div>
    `).join("")}
  `;
}

function renderDirectorRiskInsights(teamStats) {
  if (!elements.directorRiskInsights) return;

  if (!teamStats.length) {
    elements.directorRiskInsights.innerHTML = "";
    return;
  }

  const highestRiskTeam = [...teamStats].sort((a, b) => {
    const riskWeight = { high: 3, moderate: 2, low: 1 };
    return riskWeight[b.riskClass] - riskWeight[a.riskClass];
  })[0];

  const bestReadinessTeam = [...teamStats].sort((a, b) => b.readiness - a.readiness)[0];
  const lowestAttendanceTeam = [...teamStats].sort((a, b) => a.attendance - b.attendance)[0];
  const mostInjuriesTeam = [...teamStats].sort((a, b) => b.injuries - a.injuries)[0];

  elements.directorRiskInsights.innerHTML = `
    <article class="director-risk-card risk-${highestRiskTeam.riskClass}">
      <span>Highest Risk</span>
      <strong>${highestRiskTeam.name}</strong>
      <p>${highestRiskTeam.risk} risk profile</p>
    </article>

    <article class="director-risk-card risk-low">
      <span>Best Readiness</span>
      <strong>${bestReadinessTeam.name}</strong>
      <p>${bestReadinessTeam.readiness}% ready</p>
    </article>

    <article class="director-risk-card risk-moderate">
      <span>Lowest Attendance</span>
      <strong>${lowestAttendanceTeam.name}</strong>
      <p>${lowestAttendanceTeam.attendance}% attendance</p>
    </article>

    <article class="director-risk-card risk-high">
      <span>Most Injuries</span>
      <strong>${mostInjuriesTeam.name}</strong>
      <p>${mostInjuriesTeam.injuries} active injuries</p>
    </article>
  `;
}

function getCurrentWeekRecords(records) {
  const today = new Date();
  const day = today.getDay();
  const mondayOffset = day === 0 ? -6 : 1 - day;

  const monday = new Date(today);
  monday.setDate(today.getDate() + mondayOffset);
  monday.setHours(0, 0, 0, 0);

  const sunday = new Date(monday);
  sunday.setDate(monday.getDate() + 6);
  sunday.setHours(23, 59, 59, 999);

  return records.filter((record) => {
    const date = getDateValue(record);
    return date >= monday && date <= sunday;
  });
}

function renderWeeklyAttendanceChart(attendanceRecords, matchRecords = []) {
  if (!elements.weeklyAttendanceChart || typeof Chart === "undefined") return;

  if (weeklyAttendanceChartInstance) {
    weeklyAttendanceChartInstance.destroy();
  }

  const days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
  const totals = [0, 0, 0, 0, 0, 0, 0];
  const present = [0, 0, 0, 0, 0, 0, 0];
  const gameDays = [0, 0, 0, 0, 0, 0, 0];

  getCurrentWeekRecords(attendanceRecords).forEach((record) => {
    const index = getDateValue(record).getDay() === 0
      ? 6
      : getDateValue(record).getDay() - 1;

    totals[index]++;

    if (String(record.status || "").toLowerCase() === "present") {
      present[index]++;
    }
  });

  getCurrentWeekRecords(matchRecords).forEach((match) => {
    const index = getDateValue(match).getDay() === 0
      ? 6
      : getDateValue(match).getDay() - 1;

    gameDays[index] = 100;
  });

  const percentages = totals.map((total, index) => {
    if (!total) return 0;
    return Math.round((present[index] / total) * 100);
  });

  weeklyAttendanceChartInstance = new Chart(elements.weeklyAttendanceChart, {
    type: "bar",
    data: {
      labels: days,
      datasets: [
        {
          label: "Attendance %",
          data: percentages,
          backgroundColor: CHART_THEME.primary,
          borderRadius: 10,
          barThickness: 16
        },
        {
          label: "Game Day",
          data: gameDays,
          backgroundColor: "#39ff14",
          borderRadius: 10,
          barThickness: 8
        }
      ]
    },
    options: getBaseChartOptions({
      plugins: {
        legend: {
          display: true,
          labels: {
            color: CHART_THEME.text,
            boxWidth: 12,
            boxHeight: 12
          }
        },
        tooltip: getBaseChartOptions().plugins.tooltip
      },
      scales: {
        y: {
          beginAtZero: true,
          max: 100,
          ticks: {
            color: CHART_THEME.muted,
            callback: (value) => `${value}%`
          },
          grid: { color: CHART_THEME.grid }
        },
        x: {
          ticks: { color: CHART_THEME.text },
          grid: { display: false }
        }
      }
    })
  });
}

function renderWeeklyPerformanceChart(trainingSessions) {
  if (!elements.weeklyPerformanceChart || typeof Chart === "undefined") return;

  if (weeklyPerformanceChartInstance) {
    weeklyPerformanceChartInstance.destroy();
  }

  const days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
  const loads = [0, 0, 0, 0, 0, 0, 0];
  const counts = [0, 0, 0, 0, 0, 0, 0];

  trainingSessions.forEach((session) => {
    const date = getDateValue(session);
    if (!date || Number.isNaN(date.getTime())) return;

    const jsDay = date.getDay();
    const index = jsDay === 0 ? 6 : jsDay - 1;

    loads[index] += Number(session.sessionLoad || 0);
    counts[index]++;
  });

  const performanceScores = loads.map((load, index) => {
    if (!counts[index]) return 0;

    const averageLoad = load / counts[index];
    return Math.min(100, Math.round((averageLoad / 500) * 100));
  });

  weeklyPerformanceChartInstance = new Chart(elements.weeklyPerformanceChart, {
    type: "line",
    data: {
      labels: days,
      datasets: [
        {
          label: "Performance %",
          data: performanceScores,
          borderColor: "#2563eb",
          backgroundColor: "rgba(37,99,235,0.16)",
          fill: true,
          tension: 0.42,
          pointRadius: 5,
          pointHoverRadius: 7,
          pointBackgroundColor: "#2563eb",
          pointBorderColor: "#60a5fa",
          pointBorderWidth: 2
        }
      ]
    },
    options: getBaseChartOptions({
      plugins: {
        legend: { display: false },
        tooltip: getBaseChartOptions().plugins.tooltip
      },
      scales: {
        y: {
          beginAtZero: true,
          max: 100,
          ticks: {
            color: CHART_THEME.muted,
            callback: (value) => `${value}%`
          },
          grid: { color: CHART_THEME.grid }
        },
        x: {
          ticks: { color: CHART_THEME.text },
          grid: { display: false }
        }
      }
    })
  });
}

function renderWeeklyWellnessChart(wellnessRecords) {
  if (!elements.weeklyWellnessChart || typeof Chart === "undefined") return;

  if (weeklyWellnessChartInstance) {
    weeklyWellnessChartInstance.destroy();
  }

  const days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
  const totals = [0, 0, 0, 0, 0, 0, 0];
  const counts = [0, 0, 0, 0, 0, 0, 0];

  wellnessRecords.forEach((record) => {
    const date = getDateValue(record);
    if (!date || Number.isNaN(date.getTime())) return;

    const jsDay = date.getDay();
    const index = jsDay === 0 ? 6 : jsDay - 1;

    totals[index] += calculateWellnessScore(record);
    counts[index]++;
  });

  const averages = totals.map((total, index) =>
    counts[index] ? Math.round(total / counts[index]) : 0
  );

  weeklyWellnessChartInstance = new Chart(elements.weeklyWellnessChart, {
    type: "line",
    data: {
      labels: days,
      datasets: [
        {
          label: "Wellness %",
          data: averages,
          borderColor: "#22c55e",
          backgroundColor: "rgba(34,197,94,0.14)",
          fill: true,
          tension: 0.4,
          pointRadius: 5,
          pointHoverRadius: 7,
          pointBackgroundColor: "#22c55e",
          pointBorderColor: "#86efac",
          pointBorderWidth: 2
        }
      ]
    },
    options: getBaseChartOptions({
      plugins: {
        legend: { display: false },
        tooltip: getBaseChartOptions().plugins.tooltip
      },
      scales: {
        y: {
          beginAtZero: true,
          max: 100,
          ticks: {
            color: CHART_THEME.muted,
            callback: (value) => `${value}%`
          },
          grid: { color: CHART_THEME.grid }
        },
        x: {
          ticks: { color: CHART_THEME.text },
          grid: { display: false }
        }
      }
    })
  });
}

function renderPlayerRiskLeaderboard(playerRiskRows) {
  if (!elements.playerRiskLeaderboard) return;

  if (!playerRiskRows.length) {
    elements.playerRiskLeaderboard.innerHTML = `
      <div class="app-card">No player risk data available yet.</div>
    `;
    return;
  }

  const sortedRows = [...playerRiskRows]
    .sort((a, b) => b.riskScore - a.riskScore)
    .slice(0, 8);

  elements.playerRiskLeaderboard.innerHTML = `
    <div class="player-risk-header">
      <span>Player</span>
      <span>Team</span>
      <span>Wellness</span>
      <span>Attendance</span>
      <span>Injury</span>
      <span>Risk</span>
    </div>

    ${sortedRows.map((row) => `
      <div class="player-risk-row">
        <strong>${row.name}</strong>
        <span>${row.team}</span>
        <span>${row.wellness}%</span>
        <span>${row.attendance}%</span>
        <span>${row.injuryStatus}</span>
        <span class="risk-pill risk-${row.riskClass}">${row.risk}</span>
      </div>
    `).join("")}
  `;
}

async function loadDashboardStats() {
  if (dashboardRefreshIsRunning) return;

  dashboardRefreshIsRunning = true;

  try {
    if (activeProfile.role === "coach" && !hasCoachAssignments()) {
      renderNoTeamAssignedState();

      hideLoader();

      loadDashboardNotifications()
        .then(() => setupDashboardNotificationActions())
        .catch((error) => {
        console.error("Dashboard notification load error:", error);
        });

      return;
    }

    const [
      allPlayers,
      allAttendance,
      allTrainingAttendance,
      allWellness,
      allInjuries,
      allTrainingSessions,
      allTeams,
      allMatches
    ] = await Promise.all([
      getCollectionRecords("players"),
      getCollectionRecords("attendance"),
      getCollectionRecords("trainingAttendance"),
      getCollectionRecords("wellness"),
      getCollectionRecords("injuries"),
      getCollectionRecords("trainingSessions"),
      getCollectionRecords("teams"),
      getCollectionRecords("matches")
    ]);

    const players = allPlayers.filter((player) => canAccessPlayer(player));

    const accessiblePlayerIds = new Set(players.map((player) => player.id));
    const accessibleTeamIds = new Set(
      players.flatMap((player) => getPlayerTeamIds(player))
    );
    const totalTeams = accessibleTeamIds.size;

    const attendance = allAttendance.filter((record) => accessiblePlayerIds.has(record.playerId));
    const trainingAttendance = allTrainingAttendance.filter((record) => accessiblePlayerIds.has(record.playerId));
    const combinedAttendance = [...attendance, ...trainingAttendance];

    const wellness = allWellness.filter((record) => accessiblePlayerIds.has(record.playerId));
    const injuries = allInjuries.filter((record) => accessiblePlayerIds.has(record.playerId));
    const trainingSessions = allTrainingSessions.filter((session) => accessibleTeamIds.has(session.teamId));
    const matches = allMatches.filter((match) => accessibleTeamIds.has(match.teamId));
    
    const teams = allTeams.filter((team) => accessibleTeamIds.has(team.id));
    const teamNameById = new Map(
      teams.map((team) => [
        team.id,
        team.name || team.teamName || team.title || "Unnamed Team"
      ])
    );
    
    if (activeProfile.role === "director" && elements.directorComparisonSection) {
      elements.directorComparisonSection.classList.remove("hidden");
    } else if (elements.directorComparisonSection) {
      elements.directorComparisonSection.classList.add("hidden");
    }

    const attendanceByPlayer = groupByPlayerId(combinedAttendance);
    const latestWellnessByPlayer = getLatestByPlayerId(wellness);
    const activeInjuries = injuries.filter((injury) => isActiveInjury(injury));
    const activeInjuryPlayerIds = new Set(activeInjuries.map((injury) => injury.playerId));

    let readyCount = 0;
    let monitorCount = 0;
    let lowWellnessCount = 0;
    let lowAttendanceCount = 0;
    let goodWellness = 0;
    let moderateWellness = 0;
    let poorWellness = 0;
    let missingWellness = 0;
    const playerRiskRows = [];

    players.forEach((player) => {
      const playerAttendance = attendanceByPlayer.get(player.id) || [];
      const presentCount = playerAttendance.filter((record) => record.status === "present").length;
      const attendancePercentage = playerAttendance.length
        ? Math.round((presentCount / playerAttendance.length) * 100)
        : 0;

      const latestWellness = latestWellnessByPlayer.get(player.id);
      const hasWellnessRecord = Boolean(latestWellness);
      const wellnessScore = calculateWellnessScore(latestWellness);
      const hasActiveInjury = activeInjuryPlayerIds.has(player.id);
      
      const playerRiskScore =
        (hasActiveInjury ? 40 : 0) +
        (wellnessScore < 50 ? 30 : wellnessScore < 70 ? 15 : 0) +
        (attendancePercentage < 65 ? 30 : attendancePercentage < 80 ? 15 : 0);
    
      let playerRisk = "Low";
      let playerRiskClass = "low";
    
      if (playerRiskScore >= 60) {
        playerRisk = "High";
        playerRiskClass = "high";
      } else if (playerRiskScore >= 25) {
        playerRisk = "Moderate";
        playerRiskClass = "moderate";
      }
    
      if (!hasWellnessRecord) {
        missingWellness++;
      } else if (wellnessScore >= 75) {
        goodWellness++;
      } else if (wellnessScore >= 50) {
        moderateWellness++;
      } else {
        poorWellness++;
      }

      if (wellnessScore < 50) lowWellnessCount++;
      if (attendancePercentage < 65) lowAttendanceCount++;

      if (!hasActiveInjury && wellnessScore >= 70 && attendancePercentage >= 80) {
        readyCount++;
      } else {
        monitorCount++;
      }
      
      playerRiskRows.push({
        id: player.id,
        name:
          player.fullName ||
          player.name ||
          player.displayName ||
          player.playerName ||
          `${player.firstName || ""} ${player.lastName || ""}`.trim() ||
          player.email ||
          "Unnamed Player",
        team:
          player.teamNames?.length
            ? player.teamNames.join(", ")
            : getPlayerTeamIds(player)
              .map((teamId) => teamNameById.get(teamId))
              .filter(Boolean)
              .join(", ") || player.teamName || "No Team",
        wellness: wellnessScore,
        attendance: attendancePercentage,
        injuryStatus: hasActiveInjury ? "Active" : "Clear",
        risk: playerRisk,
        riskClass: playerRiskClass,
        riskScore: playerRiskScore
      });
    });

    const recentSessions = [...trainingSessions]
      .sort((a, b) => getDateValue(b) - getDateValue(a))
      .slice(0, 10);

    const totalLoad = recentSessions.reduce((sum, session) => {
      return sum + Number(session.sessionLoad || 0);
    }, 0);

    const averageTrainingLoad = recentSessions.length
      ? Math.round(totalLoad / recentSessions.length)
      : 0;

    const squadAvailabilityPercentage = players.length
      ? Math.round((readyCount / players.length) * 100)
      : 0;

    const totalWellnessScore = players.reduce((sum, player) => {
      const latestWellness = latestWellnessByPlayer.get(player.id);
      return sum + calculateWellnessScore(latestWellness);
    }, 0);

    const averageWellnessPercentage = players.length
      ? Math.round(totalWellnessScore / players.length)
      : 0;

    const totalAttendanceRecords = combinedAttendance.length;
    const presentAttendanceRecords = combinedAttendance.filter((record) => record.status === "present").length;
    const attendanceRatePercentage = totalAttendanceRecords
      ? Math.round((presentAttendanceRecords / totalAttendanceRecords) * 100)
      : 0;

    updateEliteHero({
      squadAvailabilityPercentage,
      activeInjuryCount: activeInjuries.length,
      lowWellnessCount,
      lowAttendanceCount,
      averageTrainingLoad
    });

    animateCounter(elements.totalPlayers, players.length);
    animateCounter(elements.totalTeams, totalTeams);
    animateCounter(elements.dashboardReadyPlayers, readyCount);
    animateCounter(elements.dashboardMonitorPlayers, monitorCount);

    setText(elements.dashboardWellnessScore, `${averageWellnessPercentage}%`);

    animatePremiumRing(".premium-wellness-ring", averageWellnessPercentage);
    animatePremiumRing(".premium-attendance-ring", attendanceRatePercentage);
    setText(elements.dashboardAttendanceScore, `${attendanceRatePercentage}%`);
    animateCounter(elements.injuryCount, activeInjuries.length);
    animateCounter(elements.dashboardTrainingLoad, averageTrainingLoad);

    setText(elements.dashboardLoadRisk, getDashboardLoadRisk(averageTrainingLoad));
    updateLoadRiskCard(averageTrainingLoad);

    updateStatusValue(
      elements.squadAvailability,
      `${squadAvailabilityPercentage}%`,
      squadAvailabilityPercentage >= 80 ? "status-good" : squadAvailabilityPercentage >= 60 ? "status-watch" : "status-risk"
    );

    updateStatusValue(
      elements.averageWellness,
      `${averageWellnessPercentage}%`,
      averageWellnessPercentage >= 70 ? "status-good" : averageWellnessPercentage >= 50 ? "status-watch" : "status-risk"
    );

    updateStatusValue(
      elements.attendanceRate,
      `${attendanceRatePercentage}%`,
      attendanceRatePercentage >= 80 ? "status-good" : attendanceRatePercentage >= 65 ? "status-watch" : "status-risk"
    );

    updateStatusValue(
      elements.loadStatus,
      getDashboardLoadRisk(averageTrainingLoad),
      averageTrainingLoad >= 500 ? "status-risk" : averageTrainingLoad >= 350 ? "status-watch" : "status-good"
    );

    renderRiskCategoryChart({
      lowWellnessCount,
      lowAttendanceCount,
      activeInjuryCount: activeInjuries.length,
      missingWellness,
      averageTrainingLoad
    });

    renderWellnessChart(goodWellness, moderateWellness, poorWellness, missingWellness);
    renderTrainingLoadChart(trainingSessions);
    renderWeeklyAttendanceChart(combinedAttendance, matches);
    renderWeeklyPerformanceChart(trainingSessions);
    renderWeeklyWellnessChart(wellness);
    renderPlayerRiskLeaderboard(playerRiskRows);
    
    if (activeProfile.role === "director") {
      const teamStats = Array.from(accessibleTeamIds).map((teamId) => {
        const teamPlayers = players.filter((player) =>
          getPlayerTeamIds(player).includes(teamId)
        );
        const teamName =
          teamNameById.get(teamId) ||
          teamPlayers.find((player) => player.teamName)?.teamName ||
          trainingSessions.find((session) => session.teamId === teamId)?.teamName ||
          "Unnamed Team";
    
        const teamPlayerIds = new Set(teamPlayers.map((player) => player.id));
    
        const teamAttendance = combinedAttendance.filter((record) =>
          teamPlayerIds.has(record.playerId)
        );
    
        const teamWellness = wellness.filter((record) =>
          teamPlayerIds.has(record.playerId)
        );
    
        const teamInjuries = activeInjuries.filter((injury) =>
          teamPlayerIds.has(injury.playerId)
        );
    
        const teamLatestWellness = getLatestByPlayerId(teamWellness);
        const teamAttendanceByPlayer = groupByPlayerId(teamAttendance);
        const teamInjuryPlayerIds = new Set(teamInjuries.map((injury) => injury.playerId));
    
        let teamReadyCount = 0;
        let teamWellnessTotal = 0;
    
        teamPlayers.forEach((player) => {
          const playerAttendance = teamAttendanceByPlayer.get(player.id) || [];
          const presentCount = playerAttendance.filter((record) =>
            String(record.status || "").toLowerCase() === "present"
          ).length;
    
          const playerAttendancePercentage = playerAttendance.length
            ? Math.round((presentCount / playerAttendance.length) * 100)
            : 0;
    
          const latestWellness = teamLatestWellness.get(player.id);
          const wellnessScore = calculateWellnessScore(latestWellness);
          const hasActiveInjury = teamInjuryPlayerIds.has(player.id);
    
          teamWellnessTotal += wellnessScore;
    
          if (!hasActiveInjury && wellnessScore >= 70 && playerAttendancePercentage >= 80) {
            teamReadyCount++;
          }
        });
    
        const teamPresentAttendance = teamAttendance.filter((record) =>
          String(record.status || "").toLowerCase() === "present"
        ).length;
    
        const readiness = teamPlayers.length
          ? Math.round((teamReadyCount / teamPlayers.length) * 100)
          : 0;
    
        const wellnessScore = teamPlayers.length
          ? Math.round(teamWellnessTotal / teamPlayers.length)
          : 0;
    
        const attendanceScore = teamAttendance.length
          ? Math.round((teamPresentAttendance / teamAttendance.length) * 100)
          : 0;
    
        let risk = "Low";
        let riskClass = "low";
    
        if (readiness < 60 || wellnessScore < 50 || attendanceScore < 65 || teamInjuries.length >= 3) {
          risk = "High";
          riskClass = "high";
        } else if (readiness < 75 || wellnessScore < 70 || attendanceScore < 80 || teamInjuries.length > 0) {
          risk = "Moderate";
          riskClass = "moderate";
        }
    
        return {
          id: teamId,
          name: teamName,
          readiness,
          wellness: wellnessScore,
          attendance: attendanceScore,
          injuries: teamInjuries.length,
          risk,
          riskClass
        };
      });
    
      renderTeamComparisonChart(teamStats);
      renderTeamComparisonTable(teamStats);
      renderDirectorRiskInsights(teamStats);
    }

    renderDashboardInsights({
      squadAvailabilityPercentage,
      averageWellnessPercentage,
      attendanceRatePercentage,
      activeInjuryCount: activeInjuries.length,
      averageTrainingLoad
    });

    const readyPercentage = players.length ? Math.round((readyCount / players.length) * 100) : 0;
    animatePremiumRing(".premium-ready-ring", readyPercentage);
    const monitorPercentage = players.length ? Math.round((monitorCount / players.length) * 100) : 0;
    animatePremiumRing(".premium-monitor-ring", monitorPercentage);
    const injuryPercentage = players.length ? Math.round((activeInjuries.length / players.length) * 100) : 0;
    const wellnessPercentage = players.length ? Math.round((lowWellnessCount / players.length) * 100) : 0;
    const attendancePercentage = players.length ? Math.round((lowAttendanceCount / players.length) * 100) : 0;

    updateTrendElement(elements.readyTrend, `${readyPercentage}% of squad ready`, readyPercentage >= 70 ? "trend-up" : "trend-warning");
    updateTrendElement(elements.monitorTrend, `${monitorPercentage}% needs review`, monitorPercentage >= 30 ? "trend-warning" : "trend-up");
    updateTrendElement(elements.injuryTrend, `${injuryPercentage}% injury risk`, injuryPercentage > 0 ? "trend-danger" : "trend-up");
    updateTrendElement(elements.wellnessTrend, `${wellnessPercentage}% low wellness`, wellnessPercentage > 0 ? "trend-warning" : "trend-up");
    updateTrendElement(elements.attendanceTrend, `${attendancePercentage}% low attendance`, attendancePercentage > 0 ? "trend-warning" : "trend-up");
    updateTrendElement(elements.trainingLoadTrend, `${recentSessions.length} recent sessions`, averageTrainingLoad >= 350 ? "trend-warning" : "trend-up");

    updateTrendElement(
      elements.loadRiskTrend,
      averageTrainingLoad >= 500
        ? "Overload risk detected"
        : averageTrainingLoad >= 350
          ? "High load monitoring"
          : averageTrainingLoad > 0
            ? "Load within range"
            : "No load data yet",
      averageTrainingLoad >= 500
        ? "trend-danger"
        : averageTrainingLoad >= 350
          ? "trend-warning"
          : "trend-up"
    );

    renderRecentActivity(combinedAttendance, wellness, injuries, trainingSessions);

    /* Main dashboard is now visible, so do not keep loader waiting for notifications */
    hideLoader();

    createDashboardRiskNotifications({
      activeInjuryCount: activeInjuries.length,
      lowWellnessCount,
      lowAttendanceCount,
      averageTrainingLoad
    })
      .then(() => loadDashboardNotifications())
      .then(() => setupDashboardNotificationActions())
      .catch((error) => {
      console.error("Dashboard notification refresh error:", error);
      });
  } catch (error) {
    console.error("Dashboard stats error:", error);
    showToast("Could not load dashboard stats: " + error.message, "error");
  } finally {
    dashboardRefreshIsRunning = false;
  }
}

requireAuth(async function (user, profile) {
  activeProfile = profile;

  updateDashboardGreeting(profile);
  updateDashboardViewLabel(profile);
  setupLogoutButton();

  showLoader("Loading dashboard...");

  try {
    await loadDashboardSubscription();
    await loadDashboardStats();
  } catch (error) {
    console.error("Dashboard load error:", error);
    showToast("Could not load dashboard: " + error.message, "error");
  } finally {
    hideLoader();
  }
});

setInterval(async () => {
  if (!activeProfile) return;

  try {
    await loadDashboardSubscription();
    await loadDashboardStats();
  } catch (error) {
    console.error("Dashboard auto refresh failed:", error);
  }
}, 60000);