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 {
  collection,
  getDocs,
  query,
  where
} from "https://www.gstatic.com/firebasejs/10.12.2/firebase-firestore.js";

const reportTeamFilter = document.getElementById("reportTeamFilter");
const reportList = document.getElementById("reportList");
const exportCsvBtn = document.getElementById("exportCsvBtn");

const reportTotalPlayers = document.getElementById("reportTotalPlayers");
const reportReadyPlayers = document.getElementById("reportReadyPlayers");
const reportMonitorPlayers = document.getElementById("reportMonitorPlayers");
const reportUnavailablePlayers = document.getElementById("reportUnavailablePlayers");

let activeProfile = null;
let teamsCache = [];
let playersCache = [];
let attendanceCache = [];
let trainingAttendanceCache = [];
let wellnessCache = [];
let injuriesCache = [];

function getTeamName(teamId) {
  const team = teamsCache.find((item) => item.id === teamId);
  return team ? team.name : "Unassigned";
}

function getPlayerName(player) {
  return `${player.firstName || ""} ${player.lastName || ""}`.trim() || "Unnamed Player";
}

function getPlayerTeamIds(player) {
  if (!player) return [];

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

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

  return teamIds.filter(Boolean);
}

function getPlayerTeamNames(player) {
  if (Array.isArray(player.teamNames) && player.teamNames.length) {
    return player.teamNames.join(", ");
  }

  return getPlayerTeamIds(player)
    .map((teamId) => getTeamName(teamId))
    .join(", ") || "Unassigned";
}

function canAccessTeam(teamId) {
  const role = activeProfile?.role;
  const assignedTeamIds = activeProfile?.assignedTeamIds || [];

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

  if (role === "coach" || role === "biokineticist") {
    return assignedTeamIds.includes(teamId);
  }

  return false;
}

function canAccessPlayer(player) {
  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;
}

async function getRecords(collectionName) {
  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 getDateValue(record) {
  if (record?.createdAt?.toDate) return record.createdAt.toDate();
  if (record?.createdDate) return new Date(record.createdDate);
  if (record?.date) return new Date(record.date);
  return new Date(0);
}

function buildPlayerRecordMap(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 calculateAttendance(playerId, attendanceByPlayer) {
  const records = attendanceByPlayer.get(playerId) || [];

  if (!records.length) return "0%";

  const present = records.filter((record) => {
    return String(record.status || "").toLowerCase() === "present";
  }).length;

  return `${Math.round((present / records.length) * 100)}%`;
}

function calculateWellness(playerId, wellnessByPlayer) {
  const records = wellnessByPlayer.get(playerId) || [];

  if (!records.length) return "-";

  const sorted = [...records].sort((a, b) => getDateValue(b) - getDateValue(a));
  const latest = sorted[0];

  const total =
    Number(latest.sleep || 0) +
    Number(latest.fatigue || 0) +
    Number(latest.soreness || 0);

  return `${total}/15`;
}

function calculateInjuries(playerId, injuriesByPlayer) {
  const records = injuriesByPlayer.get(playerId) || [];

  return records.filter((record) => {
    const status = String(record.status || "").toLowerCase();

    return (
      status !== "cleared" &&
      status !== "closed" &&
      status !== "resolved"
    );
  }).length;
}

function calculateReadiness(player, attendanceByPlayer, wellnessByPlayer, injuriesByPlayer) {
  const status = String(player.status || "available").toLowerCase();

  const attendance = Number(
    calculateAttendance(player.id, attendanceByPlayer).replace("%", "")
  );

  const wellness = Number(
    calculateWellness(player.id, wellnessByPlayer).replace("/15", "")
  ) || 0;

  const injuries = calculateInjuries(player.id, injuriesByPlayer);

  if (status === "injured" || status === "rehab" || injuries > 0) {
    return "Unavailable";
  }

  if (attendance < 70 || wellness >= 11) {
    return "Monitor";
  }

  return "Ready";
}

function getReadinessClass(readiness) {
  if (readiness === "Ready") return "readiness-ready";
  if (readiness === "Monitor") return "readiness-monitor";
  return "readiness-danger";
}

function getReadinessWeight(readiness) {
  if (readiness === "Unavailable") return 3;
  if (readiness === "Monitor") return 2;
  return 1;
}

function getReportRows(filteredPlayers) {
  const attendanceByPlayer = buildPlayerRecordMap([
    ...attendanceCache,
    ...trainingAttendanceCache
  ]);
  const wellnessByPlayer = buildPlayerRecordMap(wellnessCache);
  const injuriesByPlayer = buildPlayerRecordMap(injuriesCache);

  return filteredPlayers.map((player) => {
    const attendance = calculateAttendance(player.id, attendanceByPlayer);
    const wellness = calculateWellness(player.id, wellnessByPlayer);
    const injuries = calculateInjuries(player.id, injuriesByPlayer);

    const readiness = calculateReadiness(
      player,
      attendanceByPlayer,
      wellnessByPlayer,
      injuriesByPlayer
    );

    return {
      player,
      attendance,
      wellness,
      injuries,
      readiness
    };
  });
}

function renderTeamFilter() {
  reportTeamFilter.innerHTML = `<option value="all">All Teams</option>`;

  teamsCache.forEach((team) => {
    const option = document.createElement("option");

    option.value = team.id;
    option.textContent = `${team.name || "Unnamed Team"} • ${team.ageGroup || "No age group"}`;

    reportTeamFilter.appendChild(option);
  });
}

function renderReport() {
  const selectedTeam = reportTeamFilter.value || "all";

  const filteredPlayers = playersCache.filter((player) => {
    return selectedTeam === "all" || getPlayerTeamIds(player).includes(selectedTeam);
  });

  const rows = getReportRows(filteredPlayers).sort((a, b) => {
    return getReadinessWeight(b.readiness) - getReadinessWeight(a.readiness);
  });

  const readyCount = rows.filter((row) => row.readiness === "Ready").length;
  const monitorCount = rows.filter((row) => row.readiness === "Monitor").length;
  const unavailableCount = rows.filter((row) => row.readiness === "Unavailable").length;

  reportTotalPlayers.textContent = rows.length;
  reportReadyPlayers.textContent = readyCount;
  reportMonitorPlayers.textContent = monitorCount;
  reportUnavailablePlayers.textContent = unavailableCount;

  reportList.innerHTML = "";

  if (!rows.length) {
    reportList.innerHTML = `
      <div class="app-card">
        No players found for this filter.
      </div>
    `;

    return;
  }

  rows.forEach((row) => {
    const player = row.player;

    const item = document.createElement("div");
    item.className = "elite-readiness-row elite-card";

    item.innerHTML = `
      <div>
        <h3>${getPlayerName(player)}</h3>

        <p>
          ${getPlayerTeamNames(player)}
          <span class="record-separator">&bull;</span>
          ${player.position || "No position"}
          <span class="record-separator">&bull;</span>
          ${player.ageGroup || "No group"}
        </p>
      </div>

      <div class="report-metrics">
        <span class="report-pill ${getReadinessClass(row.readiness)}">
          ${row.readiness}
        </span>

        <span>Attendance: ${row.attendance}</span>
        <span>Wellness: ${row.wellness}</span>
        <span>Injuries: ${row.injuries}</span>
        <span>Status: ${player.status || "Available"}</span>
      </div>
    `;

    reportList.appendChild(item);
  });
}

async function loadReportData() {
  reportList.innerHTML = `
    <div class="app-card">
      Loading report...
    </div>
  `;

  const [
    teams,
    players,
    attendance,
    trainingAttendance,
    wellness,
    injuries
  ] = await Promise.all([
    getRecords("teams"),
    getRecords("players"),
    getRecords("attendance"),
    getRecords("trainingAttendance"),
    getRecords("wellness"),
    getRecords("injuries")
  ]);

  teamsCache = teams.filter((team) => canAccessTeam(team.id));
  playersCache = players.filter((player) => canAccessPlayer(player));

  const accessiblePlayerIds = new Set(playersCache.map((player) => player.id));

  attendanceCache = attendance.filter((record) => {
    return accessiblePlayerIds.has(record.playerId);
  });
  
  trainingAttendanceCache = trainingAttendance.filter((record) => {
    return accessiblePlayerIds.has(record.playerId);
  });

  wellnessCache = wellness.filter((record) => {
    return accessiblePlayerIds.has(record.playerId);
  });

  injuriesCache = injuries.filter((record) => {
    return accessiblePlayerIds.has(record.playerId);
  });

  renderTeamFilter();
  renderReport();
}

function exportReportToCSV() {
  const selectedTeam = reportTeamFilter.value || "all";

  const filteredPlayers = playersCache.filter((player) => {
    return selectedTeam === "all" || getPlayerTeamIds(player).includes(selectedTeam);
  });

  const rows = getReportRows(filteredPlayers);

  let csvContent =
    "Player,Team,Position,Attendance,Wellness,Injuries,Readiness\n";

  rows.forEach((row) => {
    const player = row.player;

    const csvRow = [
      `"${getPlayerName(player)}"`,
      `"${getPlayerTeamNames(player)}"`,
      `"${player.position || ""}"`,
      `"${row.attendance}"`,
      `"${row.wellness}"`,
      `"${row.injuries}"`,
      `"${row.readiness}"`
    ];

    csvContent += csvRow.join(",") + "\n";
  });

  const blob = new Blob([csvContent], {
    type: "text/csv;charset=utf-8;"
  });

  const link = document.createElement("a");
  const url = URL.createObjectURL(blob);

  link.setAttribute("href", url);

  link.setAttribute(
    "download",
    `trytrack-report-${new Date().toISOString().slice(0, 10)}.csv`
  );

  link.style.visibility = "hidden";

  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);

  URL.revokeObjectURL(url);

  showToast("Report exported successfully.", "success");
}

reportTeamFilter?.addEventListener("change", renderReport);
exportCsvBtn?.addEventListener("click", exportReportToCSV);

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

  showLoader("Loading report...");

  try {
    await loadReportData();
  } catch (error) {
    console.error("Report loading error:", error);

    reportList.innerHTML = `
      <div class="app-card">
        Error loading report: ${error.message}
      </div>
    `;

    showToast("Could not load report: " + error.message, "error");
  } finally {
    hideLoader();
  }
});