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

import {
  createUserWithEmailAndPassword,
  updateProfile
} from "https://www.gstatic.com/firebasejs/10.12.2/firebase-auth.js";

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

const registerForm = document.getElementById("registerForm");
const fullNameInput = document.getElementById("fullName");
const emailInput = document.getElementById("registerEmail");
const passwordInput = document.getElementById("registerPassword");
const confirmPasswordInput = document.getElementById("confirmPassword");
const userRoleInput = document.getElementById("userRole");
const organisationNameInput = document.getElementById("organisationName");
const organisationTypeInput = document.getElementById("organisationType");
const directorFields = document.getElementById("directorFields");
const inviteOnlyNotice = document.getElementById("inviteOnlyNotice");

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

const ROLE_HOME = {
  director: "dashboard.html",
  coach: "dashboard.html",
  player: "player-dashboard.html",
  biokineticist: "bio-dashboard.html"
};

function getRoleHome(role) {
  return ROLE_HOME[role] || "dashboard.html";
}

function normalizeRole(role) {
  const cleanRole = String(role || "").toLowerCase().trim();

  if (cleanRole === "bio") return "biokineticist";
  if (cleanRole === "biokineticist") return "biokineticist";
  if (cleanRole === "coach") return "coach";
  if (cleanRole === "player") return "player";
  if (cleanRole === "director") return "director";

  return cleanRole;
}

function updateRoleView() {
  const selectedRole = userRoleInput?.value || "director";
  const isDirector = selectedRole === "director";

  directorFields?.classList.toggle("hidden", !isDirector);
  inviteOnlyNotice?.classList.toggle("hidden", isDirector);
}

async function findPendingInvite(email) {
  const q = query(
    collection(db, "userInvites"),
    where("email", "==", email),
    where("status", "==", "pending")
  );

  const snapshot = await getDocs(q);

  if (snapshot.empty) return null;

  const inviteDoc = snapshot.docs[0];

  return {
    id: inviteDoc.id,
    ...inviteDoc.data()
  };
}

function inviteIsExpired(invite) {
  if (!invite?.expiresAt) return false;

  const expiryDate = invite.expiresAt.toDate
    ? invite.expiresAt.toDate()
    : new Date(invite.expiresAt);

  return expiryDate < new Date();
}

function setLoading(isLoading) {
  if (!submitButton) return;

  submitButton.disabled = isLoading;
  submitButton.textContent = isLoading ? "Creating Account..." : "Create Account";
}

async function createDirectorAccount({ user, fullName, email }) {
  const organisationName = organisationNameInput.value.trim();
  const organisationType = organisationTypeInput.value || "school";

  if (!organisationName) {
    throw new Error("Please enter your organisation name.");
  }

  const trialEndsAt = new Date();
  trialEndsAt.setDate(trialEndsAt.getDate() + 14);

  const organisationRef = await addDoc(collection(db, "organisations"), {
    name: organisationName,
    type: organisationType,
    status: "active",

    subscription: {
      plan: "trial",
      status: "trial",
      billingCycle: "none",
      active: true,
      trialEndsAt,
      currentPeriodEndsAt: trialEndsAt,

      limits: {
        maxTeams: 3,
        maxPlayers: 100,
        maxCoaches: 5,
        maxBiokineticists: 2
      }
    },

    createdBy: user.uid,
    createdAt: serverTimestamp(),
    updatedAt: serverTimestamp()
  });

  const userData = {
    uid: user.uid,
    fullName,
    email,
    role: "director",
    organisationId: organisationRef.id,
    status: "active",
    assignedTeamIds: [],
    assignedPlayerIds: [],
    playerId: "",
    createdAt: serverTimestamp(),
    updatedAt: serverTimestamp()
  };

  await setDoc(doc(db, "users", user.uid), userData);

  return userData;
}

async function notifyOrganisationDirectorsOfAcceptedInvite({
  invite,
  fullName,
  email
}) {
  if (!invite?.organisationId) return;

  const directorsQuery = query(
    collection(db, "users"),
    where("organisationId", "==", invite.organisationId),
    where("role", "==", "director"),
    where("status", "==", "active")
  );

  const directorsSnapshot = await getDocs(directorsQuery);

  const roleLabel =
    invite.role === "biokineticist"
      ? "Biokineticist"
      : String(invite.role || "user").charAt(0).toUpperCase() +
        String(invite.role || "user").slice(1);

  const notificationJobs = directorsSnapshot.docs.map((directorDoc) => {
    const director = directorDoc.data();

    return createNotification({
      organisationId: invite.organisationId,
      userId: director.uid || directorDoc.id,
      type: "invite_accepted",
      title: "Invited user registered",
      message: `${fullName} (${email}) has accepted the invite and joined TryTrack as ${roleLabel}.`,
      link: "user-management.html",
      severity: "success",
      uniqueKey: `invite-accepted-${invite.id}-${director.uid || directorDoc.id}`
    });
  });

  await Promise.allSettled(notificationJobs);
}

async function createInvitedAccount({
  user,
  fullName,
  email,
  invite
}) {
  const userData = {
    uid: user.uid,
    fullName,
    email,
    role: normalizeRole(invite.role),
    organisationId: invite.organisationId,
    status: "active",
    assignedTeamIds: invite.assignedTeamIds || [],
    assignedPlayerIds:
      invite.assignedPlayerIds || (invite.playerId ? [invite.playerId] : []),
    playerId: invite.playerId || "",
    createdAt: serverTimestamp(),
    updatedAt: serverTimestamp()
  };

  await setDoc(doc(db, "users", user.uid), userData);

  await updateDoc(doc(db, "userInvites", invite.id), {
    status: "accepted",
    acceptedBy: user.uid,
    acceptedAt: serverTimestamp(),
    updatedAt: serverTimestamp()
  });

  await notifyOrganisationDirectorsOfAcceptedInvite({
    invite,
    fullName,
    email
  });

  return userData;
}

userRoleInput?.addEventListener("change", updateRoleView);
updateRoleView();

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

  const fullName = fullNameInput.value.trim();
  const email = emailInput.value.trim().toLowerCase();
  const password = passwordInput.value;
  const confirmPassword = confirmPasswordInput.value;
  const selectedRole = normalizeRole(userRoleInput.value);

  if (!fullName || !email || !password || !confirmPassword || !selectedRole) {
    showToast("Please complete all fields.", "warning");
    return;
  }

  if (password !== confirmPassword) {
    showToast("Passwords do not match.", "warning");
    return;
  }

  if (password.length < 6) {
    showToast("Password must be at least 6 characters.", "warning");
    return;
  }

  showLoader("Creating your TryTrack account...");
  setLoading(true);

  try {
    let pendingInvite = null;

    if (selectedRole !== "director") {
      pendingInvite = await findPendingInvite(email);

      if (!pendingInvite) {
        throw new Error("No active invite found for this email address.");
      }

      if (inviteIsExpired(pendingInvite)) {
        throw new Error("This invite has expired. Please ask for a new invite.");
      }

      const inviteRole = normalizeRole(pendingInvite.role);

      if (inviteRole !== selectedRole) {
        throw new Error(`This invite is for a ${inviteRole} account, not ${selectedRole}.`);
      }
    
      pendingInvite.role = inviteRole;
    }

    const result = await createUserWithEmailAndPassword(auth, email, password);

    await updateProfile(result.user, {
      displayName: fullName
    });

    const profile =
      selectedRole === "director"
        ? await createDirectorAccount({
            user: result.user,
            fullName,
            email
          })
        : await createInvitedAccount({
          user: result.user,
          fullName,
          email,
          invite: pendingInvite
        });

    showToast("Account created successfully.", "success");

    window.location.href = getRoleHome(profile.role);
  } catch (error) {
    console.error("Registration error:", error);
    showToast("Registration failed: " + error.message, "error");
  } finally {
    setLoading(false);
    hideLoader();
  }
});