// =========================================================
// FILE: notifications.js | TYPE: Notifications 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,
  query,
  where,
  doc,
  updateDoc,
  serverTimestamp,
  onSnapshot
} from "https://www.gstatic.com/firebasejs/10.12.2/firebase-firestore.js";

const notificationList = document.getElementById("notificationList");

const notificationTotal = document.getElementById("notificationTotal");
const notificationHighRisk = document.getElementById("notificationHighRisk");
const notificationMonitor = document.getElementById("notificationMonitor");
const notificationMatches = document.getElementById("notificationMatches");

const notificationTypeFilter = document.getElementById("notificationTypeFilter");
const notificationReadFilter = document.getElementById("notificationReadFilter");
const markAllReadBtn = document.getElementById("markAllReadBtn");

let activeProfile = null;
let notificationsCache = [];
let unsubscribeNotifications = [];

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

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

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

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

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

function formatDate(record) {
  const date = getDateValue(record);

  if (!date || date.getTime() === 0) return "No date";

  return date.toLocaleDateString("en-ZA", {
    year: "numeric",
    month: "short",
    day: "numeric"
  });
}

function canAccessNotification(notification) {
  if (!activeProfile || !notification) return false;

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

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

  if (role === "coach") {
    return Boolean(notification.teamId && assignedTeamIds.includes(notification.teamId));
  }

  if (role === "biokineticist") {
    return (
      Boolean(notification.teamId && assignedTeamIds.includes(notification.teamId)) ||
      Boolean(notification.playerId && assignedPlayerIds.includes(notification.playerId)) ||
      notification.userId === activeProfile.uid
    );
  }

  if (role === "player") {
    const isOwnUserNotification =
      notification.userId === activeProfile.uid;

    const isOwnPlayerNotification =
      notification.playerId === activeProfile.playerId;

    const isTeamWideNotification =
      notification.teamId &&
      assignedTeamIds.includes(notification.teamId) &&
      (!notification.playerId || notification.playerId === "") &&
      (!notification.userId || notification.userId === "");

    return (
      isOwnUserNotification ||
      isOwnPlayerNotification ||
      isTeamWideNotification
    );
  }

  return false;
}

function getFilteredNotifications() {
  const typeFilter = notificationTypeFilter?.value || "all";
  const readFilter = notificationReadFilter?.value || "unread";

  let filteredNotifications =
    typeFilter === "all"
      ? [...notificationsCache]
      : notificationsCache.filter((item) => item.type === typeFilter);

  if (readFilter === "unread") {
    filteredNotifications = filteredNotifications.filter(
      (item) => !isNotificationRead(item)
    );
  }

  if (readFilter === "read") {
    filteredNotifications = filteredNotifications.filter(
      (item) => isNotificationRead(item)
    );
  }

  return filteredNotifications;
}

function mergeNotificationSnapshots(snapshots) {
  const notificationMap = new Map();

  snapshots.forEach((snapshot) => {
    snapshot.docs.forEach((docSnap) => {
      notificationMap.set(docSnap.id, {
        id: docSnap.id,
        ...docSnap.data()
      });
    });
  });

  notificationsCache = Array.from(notificationMap.values())
    .filter((notification) => canAccessNotification(notification))
    .sort((a, b) => getDateValue(b) - getDateValue(a));

  renderNotifications();
}

async function loadNotifications() {
  if (!notificationList || !activeProfile?.organisationId) return;

  showLoader("Loading notifications...");

  notificationList.innerHTML = `
    <div class="app-card">
      Loading notifications...
    </div>
  `;

  const loaderSafetyTimer = setTimeout(() => {
    hideLoader();
  }, 5000);

  try {
    if (unsubscribeNotifications.length) {
      unsubscribeNotifications.forEach((unsubscribe) => unsubscribe());
      unsubscribeNotifications = [];
    }

    const snapshotsCache = [];

    function handleSnapshot(index, snapshot) {
      snapshotsCache[index] = snapshot;
      mergeNotificationSnapshots(snapshotsCache.filter(Boolean));
      clearTimeout(loaderSafetyTimer);
      hideLoader();
    }

    function handleError(error) {
      console.error("Notification listener error:", error);
      clearTimeout(loaderSafetyTimer);
      hideLoader();

      notificationList.innerHTML = `
        <div class="app-card">
          <strong>Could not load notifications.</strong>
          <p>${error.message}</p>
        </div>
      `;

      showToast("Could not load notifications: " + error.message, "error");
    }

    if (activeProfile.role === "player") {
      const playerQueries = [];

      if (activeProfile.playerId) {
        playerQueries.push(
          query(
            collection(db, "notifications"),
            where("organisationId", "==", activeProfile.organisationId),
            where("playerId", "==", activeProfile.playerId)
          )
        );
      }

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

      const assignedTeamIds = activeProfile.assignedTeamIds || [];

      assignedTeamIds.slice(0, 10).forEach((teamId) => {
        playerQueries.push(
          query(
            collection(db, "notifications"),
            where("organisationId", "==", activeProfile.organisationId),
            where("teamId", "==", teamId)
          )
        );
      });

      unsubscribeNotifications = playerQueries.map((notificationQuery, index) =>
        onSnapshot(
          notificationQuery,
          (snapshot) => handleSnapshot(index, snapshot),
          handleError
        )
      );

      return;
    }

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

    unsubscribeNotifications = [
      onSnapshot(
        notificationsQuery,
        (snapshot) => handleSnapshot(0, snapshot),
        handleError
      )
    ];
  } catch (error) {
    console.error("Notification setup error:", error);
    clearTimeout(loaderSafetyTimer);
    hideLoader();

    notificationList.innerHTML = `
      <div class="app-card">
        <strong>Could not setup notifications.</strong>
        <p>${error.message}</p>
      </div>
    `;

    showToast("Could not setup notifications: " + error.message, "error");
  }
}

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

async function markAllVisibleNotificationsAsRead() {
  const visibleNotifications = getFilteredNotifications();
  const unreadNotifications = visibleNotifications.filter(
    (item) => !isNotificationRead(item)
  );

  if (!unreadNotifications.length) {
    showToast("There are no unread notifications to mark as read.", "info");
    return;
  }

  await Promise.all(
    unreadNotifications.map((notification) =>
      updateDoc(doc(db, "notifications", notification.id), {
        ...getReadByUpdate(),
        updatedAt: serverTimestamp()
      })
    )
  );
}

function renderCounters(filteredNotifications) {
  setText(notificationTotal, filteredNotifications.length);

  setText(
    notificationHighRisk,
    filteredNotifications.filter((item) => {
      return item.severity === "danger" || item.severity === "high";
    }).length
  );

  setText(
    notificationMonitor,
    filteredNotifications.filter((item) => {
      return item.severity === "warning" || item.severity === "monitor";
    }).length
  );

  setText(
    notificationMatches,
    filteredNotifications.filter((item) => item.type === "match").length
  );
}

function getSeverityLabel(severity) {
  const cleanSeverity = String(severity || "info").toLowerCase();

  if (cleanSeverity === "danger" || cleanSeverity === "high") return "High Risk";
  if (cleanSeverity === "warning" || cleanSeverity === "monitor") return "Monitor";
  return "Info";
}

function formatNotificationType(type) {
  const cleanType = String(type || "").toLowerCase();

  if (cleanType === "dashboard_alert") {
    return "Dashboard Alert";
  }

  if (cleanType === "user") {
    return "User Access";
  }

  if (cleanType === "wellness") {
    return "Wellness";
  }

  if (cleanType === "attendance") {
    return "Attendance";
  }

  if (cleanType === "injury") {
    return "Injury";
  }

  if (cleanType === "match") {
    return "Match";
  }
  
  if (cleanType === "selection") {
    return "Selection"; 
  }
  
  if (cleanType === "announcement") {
    return "Coach Announcement";
  }
  
  if (cleanType === "training") {
    return "Training Update";
  }

  if (cleanType === "load") {
    return "Training Load";
  }

  return "Notification";
}

function renderNotifications() {
  if (!notificationList) return;

  const filteredNotifications = getFilteredNotifications();

  notificationList.innerHTML = "";
  renderCounters(filteredNotifications);

  if (!filteredNotifications.length) {
    notificationList.innerHTML = `
      <div class="app-card">
        <strong>No notifications found.</strong>
        <p>There are no alerts matching the current filters.</p>
      </div>
    `;
    return;
  }

  filteredNotifications.forEach((notification) => {
    const item = document.createElement("article");

    item.className = `
      notification-item
      elite-notification-card
      notification-${notification.severity || "info"}
      ${isNotificationRead(notification) ? "notification-read" : ""}
    `;

    item.innerHTML = `
      <div class="notification-content">
        <div class="notification-header">
          <div>
            <span class="elite-notification-type">
              ${formatNotificationType(notification.type)}
            </span>

            <h3>${notification.title || "Notification"}</h3>
          </div>

          <span class="status-pill ${isNotificationRead(notification) ? "" : "status-live"}">
            ${isNotificationRead(notification) ? "Read" : "Unread"}
          </span>
        </div>

        <p>${notification.message || ""}</p>

        <small class="small-text">
          ${getSeverityLabel(notification.severity)}
          ${notification.teamName ? " • " + notification.teamName : ""}
          ${notification.playerName ? " • " + notification.playerName : ""}
          • ${formatDate(notification)}
        </small>

        <div class="record-actions">
          ${
            notification.link
              ? `<a href="${notification.link}" class="btn-secondary">Open</a>`
              : ""
          }

          ${
            isNotificationRead(notification)
              ? ""
              : `
                <button
                  class="btn-primary mark-read-btn"
                  data-id="${notification.id}"
                  type="button"
                >
                  Mark as Read
                </button>
              `
          }
        </div>
      </div>
    `;

    notificationList.appendChild(item);
  });
}

notificationList?.addEventListener("click", async function (event) {
  const markReadBtn = event.target.closest(".mark-read-btn");

  if (!markReadBtn) return;

  const notificationId = markReadBtn.dataset.id;

  if (!notificationId) return;

  try {
    markReadBtn.disabled = true;
    markReadBtn.textContent = "Updating...";

    await markNotificationAsRead(notificationId);

    showToast("Notification marked as read.", "success");
  } catch (error) {
    console.error("Mark notification read error:", error);
    showToast("Could not mark notification as read: " + error.message, "error");

    markReadBtn.disabled = false;
    markReadBtn.textContent = "Mark as Read";
  }
});

markAllReadBtn?.addEventListener("click", async function () {
  try {
    markAllReadBtn.disabled = true;
    markAllReadBtn.textContent = "Updating...";

    await markAllVisibleNotificationsAsRead();

    showToast("Visible notifications marked as read.", "success");
  } catch (error) {
    console.error("Mark all read error:", error);
    showToast("Could not mark all notifications as read: " + error.message, "error");
  } finally {
    markAllReadBtn.disabled = false;
    markAllReadBtn.textContent = "Mark All as Read";
  }
});

notificationTypeFilter?.addEventListener("change", renderNotifications);
notificationReadFilter?.addEventListener("change", renderNotifications);

window.addEventListener("beforeunload", function () {
  if (unsubscribeNotifications.length) {
    unsubscribeNotifications.forEach((unsubscribe) => unsubscribe());
  }
});

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

  await loadNotifications();
});