// =========================================================
// FILE: attendance.js | TYPE: Attendance 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 {
  collection,
  addDoc,
  getDocs,
  serverTimestamp,
  query,
  where,
  doc,
  updateDoc,
  deleteDoc,
  setDoc
} from "https://www.gstatic.com/firebasejs/10.12.2/firebase-firestore.js";

const attendanceForm = document.getElementById("attendanceForm");
const attendanceList = document.getElementById("attendanceList");
const attendancePlayer = document.getElementById("attendancePlayer");
const attendanceDate = document.getElementById("attendanceDate");
const attendanceStatus = document.getElementById("attendanceStatus");
const attendanceTeamFilter = document.getElementById("attendanceTeamFilter");

let activeProfile = null;
let playersCache = [];
let teamsCache = [];
let attendanceCache = [];
let editingAttendanceId = null;

const submitButton = attendanceForm
  ? attendanceForm.querySelector("button[type='submit']")
  : null;

function setButtonLoading(isLoading, text = "Saving...") {
  if (!submitButton) return;

  submitButton.disabled = isLoading;
  submitButton.textContent = isLoading
    ? text
    : editingAttendanceId
      ? "Update Attendance"
      : "Save Attendance";
}

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

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

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 getPlayerTeamNames(player) {
  if (Array.isArray(player.teamNames) && player.teamNames.length) {
    return player.teamNames;
  }

  return getPlayerTeamIds(player).map((teamId) => getTeamName(teamId));
}

function resetFormMode() {
  editingAttendanceId = null;

  if (attendanceForm) {
    attendanceForm.reset();
  }

  if (submitButton) {
    submitButton.textContent = "Save Attendance";
    submitButton.disabled = false;
  }

  if (attendanceDate) {
    attendanceDate.valueAsDate = new Date();
  }
}

function canAccessTeam(teamId) {
  if (!activeProfile) return false;

  const role = activeProfile.role;
  const assignedTeamIds = activeProfile.assignedTeamIds || [];

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

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

  return false;
}

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" || 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 canAccessAttendance(record) {
  if (!activeProfile || !record) return false;

  const role = activeProfile.role;
  const assignedTeamIds = activeProfile.assignedTeamIds || [];
  const assignedPlayerIds = activeProfile.assignedPlayerIds || [];
  const recordTeamIds = Array.isArray(record.teamIds)
    ? record.teamIds
    : record.teamId
      ? [record.teamId]
      : [];

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

  if (role === "coach" || role === "biokineticist") {
    return (
      recordTeamIds.some((teamId) => assignedTeamIds.includes(teamId)) ||
      assignedPlayerIds.includes(record.playerId)
    );
  }

  if (role === "player") {
    return (
      record.playerId === activeProfile.playerId ||
      playersCache.some((player) => {
        return player.id === record.playerId &&
          (
            player.userId === activeProfile.uid ||
            player.id === activeProfile.playerId
          );
      })
    );
  }

  return false;
}

function getDateValue(record) {
  if (record?.createdAt?.toDate) return record.createdAt.toDate();
  if (record?.date) return new Date(record.date);
  return new Date(0);
}

function sortAttendanceCache() {
  attendanceCache.sort((a, b) => getDateValue(b) - getDateValue(a));
}

async function createAttendanceNotification(attendanceId, attendanceData) {
  const status = String(attendanceData.status || "").toLowerCase();
  const notificationRef = doc(db, "notifications", `attendance-${attendanceId}`);

  if (status === "present") {
    await deleteDoc(notificationRef).catch(() => {});
    return;
  }

  const isAbsent = status === "absent";
  const isExcused = status === "excused";

  await setDoc(notificationRef, {
    sourceId: attendanceId,
    sourceCollection: "attendance",
    type: "attendance",
    severity: isAbsent ? "monitor" : "info",
    title: isAbsent ? "Training Attendance Missed" : "Attendance Excused",
    message: isAbsent
      ? `${attendanceData.playerName || "Player"} was marked absent on ${attendanceData.date || "No date"}.`
      : `${attendanceData.playerName || "Player"} was marked excused on ${attendanceData.date || "No date"}.`,
    link: "attendance.html",
    playerId: attendanceData.playerId || "",
    playerName: attendanceData.playerName || "",
    teamId: attendanceData.teamId || "",
    teamName: attendanceData.teamName || "",
    organisationId: activeProfile.organisationId,
    readBy: {},
    createdAt: serverTimestamp(),
    updatedAt: serverTimestamp()
  });
}

async function loadPageData() {
  const teamsQuery = query(
    collection(db, "teams"),
    where("organisationId", "==", activeProfile.organisationId)
  );

  const playersQuery = query(
    collection(db, "players"),
    where("organisationId", "==", activeProfile.organisationId)
  );

  const attendanceQuery = query(
    collection(db, "attendance"),
    where("organisationId", "==", activeProfile.organisationId)
  );

  const [teamsSnapshot, playersSnapshot, attendanceSnapshot] = await Promise.all([
    getDocs(teamsQuery),
    getDocs(playersQuery),
    getDocs(attendanceQuery)
  ]);

  teamsCache = teamsSnapshot.docs
    .map((docSnap) => ({
      id: docSnap.id,
      ...docSnap.data()
    }))
    .filter((team) => canAccessTeam(team.id));

  playersCache = playersSnapshot.docs
    .map((docSnap) => ({
      id: docSnap.id,
      ...docSnap.data()
    }))
    .filter((player) => canAccessPlayer(player));

  attendanceCache = attendanceSnapshot.docs
    .map((docSnap) => ({
      id: docSnap.id,
      ...docSnap.data()
    }))
    .filter((record) => canAccessAttendance(record));

  sortAttendanceCache();
}

function renderTeamFilter() {
  if (!attendanceTeamFilter) return;

  attendanceTeamFilter.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"}`;
    attendanceTeamFilter.appendChild(option);
  });
}

function renderPlayerDropdown() {
  if (!attendancePlayer) return;

  attendancePlayer.innerHTML = `<option value="">Select player</option>`;

  const selectedTeamFilter = attendanceTeamFilter?.value || "all";

  const availablePlayers = playersCache.filter((player) => {
    const teamIds = getPlayerTeamIds(player);
    return selectedTeamFilter === "all" || teamIds.includes(selectedTeamFilter);
  });

  if (!availablePlayers.length) {
    attendancePlayer.innerHTML = `<option value="">No players available</option>`;
    return;
  }

  const sortedPlayers = [...availablePlayers].sort((a, b) => {
    return getPlayerName(a).toLowerCase().localeCompare(getPlayerName(b).toLowerCase());
  });

  sortedPlayers.forEach((player) => {
    const option = document.createElement("option");
    option.value = player.id;
    option.textContent = `${getPlayerName(player)} • ${getPlayerTeamNames(player).join(", ")}`;
    attendancePlayer.appendChild(option);
  });
}

function getStatusClass(status) {
  const cleanStatus = String(status || "present").toLowerCase();

  if (cleanStatus === "present") return "status-low";
  if (cleanStatus === "absent") return "status-high";
  if (cleanStatus === "excused") return "status-medium";

  return "status-low";
}

function renderAttendance() {
  if (!attendanceList) return;

  attendanceList.innerHTML = "";

  const selectedTeamFilter = attendanceTeamFilter?.value || "all";

  const filteredAttendance = attendanceCache.filter((record) => {
    const teamIds = Array.isArray(record.teamIds)
      ? record.teamIds
      : record.teamId
      ? [record.teamId]
      : [];

  return selectedTeamFilter === "all" || teamIds.includes(selectedTeamFilter);
  });

  if (!filteredAttendance.length) {
    attendanceList.innerHTML = `
      <div class="app-card">
        <strong>No attendance records yet.</strong>
        <p>Capture your first attendance record using the form above.</p>
      </div>
    `;
    return;
  }

  filteredAttendance.forEach((record) => {
    const status = record.status || "present";

    const item = document.createElement("div");
    item.className = "attendance-card app-card";

    item.innerHTML = `
      <div>
        <h3>${record.playerName || "Unknown Player"}</h3>
        <p>
          ${record.teamName || "No team"}
          <span class="record-separator">&bull;</span>
          ${record.date || "No date"}
        </p>
      </div>

      <div class="record-actions">
        <span class="status-pill ${getStatusClass(status)}">
          ${status}
        </span>

        ${
          activeProfile.role === "player"
            ? ""
            : `
              <button class="btn-secondary edit-attendance-btn" data-id="${record.id}" type="button">
                Edit
              </button>

              <button class="btn-danger delete-attendance-btn" data-id="${record.id}" type="button">
                Delete
              </button>
            `
          }
      </div>
    `;

    attendanceList.appendChild(item);
  });
}

attendanceForm?.addEventListener("submit", async function (event) {
  event.preventDefault();

  if (activeProfile.role === "player") {
    showToast("Players can view attendance but cannot edit it.", "warning");
    return;
  }

  const playerId = attendancePlayer?.value;
  const date = attendanceDate?.value;
  const status = attendanceStatus?.value || "present";

  const selectedPlayer = playersCache.find((player) => player.id === playerId);

  if (!selectedPlayer) {
    showToast("Please select a player.", "warning");
    return;
  }

  if (!date) {
    showToast("Please select an attendance date.", "warning");
    return;
  }

  if (!canAccessPlayer(selectedPlayer)) {
    showToast("You do not have access to this player.", "error");
    return;
  }

  const playerTeamIds = getPlayerTeamIds(selectedPlayer);
  const playerTeamNames = getPlayerTeamNames(selectedPlayer);
  const primaryTeamId = selectedPlayer.primaryTeamId || selectedPlayer.teamId || playerTeamIds[0] || "";
  const teamName = playerTeamNames.join(", ");
  const playerName = getPlayerName(selectedPlayer);

  const attendanceData = {
    playerId,
    playerName,
    teamId: primaryTeamId,
    teamIds: playerTeamIds,
    teamName,
    teamNames: playerTeamNames,
    date,
    status,
    organisationId: activeProfile.organisationId,
    updatedAt: serverTimestamp()
  };

  setButtonLoading(true, editingAttendanceId ? "Updating..." : "Saving...");

  try {
    if (editingAttendanceId) {
      await updateDoc(doc(db, "attendance", editingAttendanceId), attendanceData);
      await createAttendanceNotification(editingAttendanceId, attendanceData);

      attendanceCache = attendanceCache.map((record) =>
        record.id === editingAttendanceId
          ? {
              ...record,
              ...attendanceData,
              updatedAt: new Date()
            }
          : record
      );

      showToast("Attendance record updated successfully.", "success");
    } else {
      const attendanceRef = await addDoc(collection(db, "attendance"), {
        ...attendanceData,
        createdBy: activeProfile.uid,
        createdAt: serverTimestamp()
      });

      await createAttendanceNotification(attendanceRef.id, attendanceData);

      attendanceCache.unshift({
        id: attendanceRef.id,
        ...attendanceData,
        createdBy: activeProfile.uid,
        createdAt: new Date()
      });

      showToast("Attendance saved successfully.", "success");
    }

    sortAttendanceCache();
    resetFormMode();
    renderAttendance();
  } catch (error) {
    console.error("Error saving attendance:", error);
    showToast("Could not save attendance: " + error.message, "error");
  } finally {
    setButtonLoading(false);
  }
});

attendanceList?.addEventListener("click", async function (event) {
  const editBtn = event.target.closest(".edit-attendance-btn");
  const deleteBtn = event.target.closest(".delete-attendance-btn");

  if (editBtn) {
    const recordId = editBtn.dataset.id;
    const record = attendanceCache.find((item) => item.id === recordId);

    if (!record) return;

    editingAttendanceId = record.id;

    if (attendancePlayer) attendancePlayer.value = record.playerId || "";
    if (attendanceDate) attendanceDate.value = record.date || "";
    if (attendanceStatus) attendanceStatus.value = record.status || "present";
    if (submitButton) submitButton.textContent = "Update Attendance";

    window.scrollTo({ top: 0, behavior: "smooth" });
  }

  if (deleteBtn) {
    const recordId = deleteBtn.dataset.id;

    const confirmed = confirm("Are you sure you want to delete this attendance record?");
    if (!confirmed) return;

    deleteBtn.disabled = true;
    deleteBtn.textContent = "Deleting...";

    try {
      await deleteDoc(doc(db, "attendance", recordId));
      await deleteDoc(doc(db, "notifications", `attendance-${recordId}`)).catch(() => {});

      attendanceCache = attendanceCache.filter((record) => record.id !== recordId);

      renderAttendance();
      showToast("Attendance record deleted.", "success");
    } catch (error) {
      console.error("Error deleting attendance:", error);
      showToast("Could not delete attendance: " + error.message, "error");
    } finally {
      deleteBtn.disabled = false;
      deleteBtn.textContent = "Delete";
    }
  }
});

attendanceTeamFilter?.addEventListener("change", function () {
  renderPlayerDropdown();
  renderAttendance();
});

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

  showLoader("Loading attendance...");

  if (attendanceList) {
    attendanceList.innerHTML = `
      <div class="app-card">Loading attendance records...</div>
    `;
  }

  try {
    if (!activeProfile?.organisationId) {
      throw new Error("No organisationId found on user profile.");
    }

    await loadPageData();

    renderTeamFilter();
    renderPlayerDropdown();
    renderAttendance();
    resetFormMode();
  } catch (error) {
    console.error("Error loading attendance:", error);

    if (attendanceList) {
      attendanceList.innerHTML = `
        <div class="app-card">
          <strong>Error loading attendance.</strong>
          <p>${error.message}</p>
        </div>
      `;
    }

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