import {
  createUser,
  deleteStudent,
  deleteUser,
  getStudents,
  getUsers,
  User,
} from '../api/Users';
import { createTeam, getTeams, Team } from '../api/Teams';
import { getRequests } from '../api/Requests';
import { FetchError } from './FetchHelper';

function parseCSV(CSVData: any) {
  const header = CSVData.shift();
  const nameIndex = header.findIndex((item: string) => item === 'Student');
  const emailIndex = header.findIndex(
    (item: string) => item === 'SIS Login ID'
  );
  const sectionIDIndex = header.findIndex((item: string) => item === 'Section');
  const teamNumIndex = header.findIndex((item: string) => item === 'Team #');
  if (
    nameIndex === -1 ||
    emailIndex === -1 ||
    sectionIDIndex === -1 ||
    teamNumIndex === -1
  ) {
    return null;
  }

  let studentData: any[] = [];
  let teamData: Team[] = [];
  for (let i = 0; i < CSVData.length; i++) {
    const name = String(CSVData[i][nameIndex]);
    let firstName = name.substring(name.indexOf(',') + 1).trim();
    // Cut off middle name/initial
    firstName = firstName.includes(' ')
      ? firstName.substring(0, firstName.indexOf(' ')).trim()
      : firstName;
    let lastName = name.substring(0, name.indexOf(',')).trim();

    let sectionID = String(CSVData[i][sectionIDIndex]).split('-')[3];

    studentData.push({
      first_name: firstName,
      last_name: lastName,
      email_address: CSVData[i][emailIndex],
      section_id: Number(sectionID),
      team_num: CSVData[i][teamNumIndex],
    });

    let foundTeam = teamData.find(
      (team) =>
        team.section_id === Number(sectionID) &&
        team.team_num === Number(CSVData[i][teamNumIndex])
    );
    if (!foundTeam) {
      teamData.push({
        team_num: Number(CSVData[i][teamNumIndex]),
        section_id: Number(sectionID),
      });
    }
  }

  return { student_data: studentData, team_data: teamData };
}

export async function addRosterFromCSV(CSVData: any) {
  let parsedDataTuple = parseCSV(CSVData);
  if (!parsedDataTuple) {
    throw new Error(
      'Failed to import roster. The CSV header row is not valid.'
    );
  }

  let APICreationErrors: FetchError[] = [];
  let existingTeams: Team[] = await getTeams();
  if (parsedDataTuple?.team_data) {
    for (let i = 0; i < parsedDataTuple?.team_data.length; i++) {
      let foundTeam = existingTeams.find(
        (team) =>
          team.section_id ===
            Number(parsedDataTuple?.team_data[i].section_id) &&
          team.team_num === Number(parsedDataTuple.team_data[i].team_num)
      );
      if (!foundTeam) {
        try {
          await createTeam({
            team_num: parsedDataTuple.team_data[i].team_num,
            section_id: parsedDataTuple.team_data[i].section_id,
          });
        } catch (error: any) {
          APICreationErrors.push(error);
        }
      }
    }
  }

  existingTeams = await getTeams();
  let existingUsers: User[] = await getUsers('student');
  if (parsedDataTuple?.student_data) {
    for (let i = 0; i < parsedDataTuple?.student_data.length; i++) {
      const foundUser = existingUsers.find(
        (user) =>
          user.email_address === parsedDataTuple.student_data[i].email_address
      );
      if (!foundUser) {
        let foundTeam = existingTeams.find(
          (team) =>
            team.team_num ===
              Number(parsedDataTuple.student_data[i].team_num) &&
            team.section_id ===
              Number(parsedDataTuple.student_data[i].section_id)
        );
        if (foundTeam) {
          try {
            await createUser({
              first_name: parsedDataTuple.student_data[i].first_name,
              last_name: parsedDataTuple.student_data[i].last_name,
              email_address: parsedDataTuple.student_data[i].email_address,
              type: 'student',
              section_id: parsedDataTuple.student_data[i].section_id,
              team_id: foundTeam.team_id,
            });
          } catch (error: any) {
            APICreationErrors.push(error);
          }
        }
      }
    }
  }

  return APICreationErrors;
}

export async function getStaleUsers(CSVData: any) {
  const parsedDataTuple = parseCSV(CSVData);

  let emailsInCSV: any[] = [];
  if (parsedDataTuple?.student_data) {
    for (let i = 0; i < parsedDataTuple?.student_data.length; i++) {
      emailsInCSV.push(parsedDataTuple.student_data[i].email_address);
    }
  }

  let staleUsers: any[] = [];
  let usersInDatabase = await getUsers('student');
  let studentsInDatabase = await getStudents();
  let requestsInDatabase = await getRequests();
  let teamsInDatabase = await getTeams();
  for (let i = 0; i < usersInDatabase.length; i++) {
    if (
      usersInDatabase[i].email_address &&
      emailsInCSV.includes(usersInDatabase[i].email_address) === false
    ) {
      // Get the student ID associated with the user
      let additionalUserInformation = studentsInDatabase.find(
        (item) => item.user_id === usersInDatabase[i].user_id
      );
      let studentID = additionalUserInformation?.student_id;

      // Check if the user is referenced in the requests table
      // If so, the user cannot be deleted
      let requestReferencingStudent = requestsInDatabase.find(
        (item) => item.student_id === Number(studentID)
      );
      let canBeDeleted = requestReferencingStudent ? false : true;

      staleUsers.push({
        user_id: usersInDatabase[i].user_id,
        name:
          usersInDatabase[i].first_name + ' ' + usersInDatabase[i].last_name,
        section_id: additionalUserInformation?.section_id,
        team_num: teamsInDatabase.find(
          (team) => team.team_id === additionalUserInformation?.team_id
        )?.team_num,
        can_be_deleted: canBeDeleted,
      });
    }
  }
  return staleUsers;
}

export async function removeStaleUsers(usersToRemove: number[]) {
  const students = await getStudents();

  // Delete student subtype records first
  for (let i = 0; i < usersToRemove.length; i++) {
    let studentRecord = students.find(
      (item: { user_id: number }) => item.user_id === usersToRemove[i]
    );
    if (studentRecord) {
      await deleteStudent(studentRecord.student_id);
    }
  }

  // Delete user records
  for (let i = 0; i < usersToRemove.length; i++) {
    await deleteUser(usersToRemove[i]);
  }
}
