import api, { activiteService, adminService, athleteService, coachService, sessionService } from "./api";
import { Activite, Admin, Athlete, Coach, Session, User } from "./classes";
import Keycloak from 'keycloak-js'
import { AdminDTO, AthleteDTO, CoachDTO, SessionDTO } from "./classesDTO";
import { useLocalData } from "./context/useLocalData";

//debug:
export function delay(ms: number): Promise<void> {
  return new Promise(resolve => setTimeout(resolve, ms));
}

//UPDATE /////////////////////////////////////////////////////////

//COACH / ATHLETE

/*
retourne l'utilisateur lié à l'identifiant keyloack
*/
export async function loginOrRegister(keycloak:Keycloak): Promise<User|null>{
    try {
        if(keycloak.tokenParsed!=null){
        const roles = keycloak.tokenParsed?.realm_access?.roles
        if(roles!=null){
            if(roles.includes("admin")){
                const newAdmin: Admin = new Admin();
                newAdmin.keycloakId = keycloak.tokenParsed.sub || "";
                newAdmin.email = keycloak.tokenParsed.email || "";
                newAdmin.nom = keycloak.tokenParsed.family_name || "";
                newAdmin.prenom = keycloak.tokenParsed.given_name || "";
                console.log(newAdmin.keycloakId);
                console.log(newAdmin.toDTO().id_keycloak);
                const response = await adminService.create(newAdmin.toDTO());
                const admin = new Admin(response.data);
                return admin;
            }
            else if(roles.includes("coach")){
                const newCoach: Coach = new Coach();
                newCoach.keycloakId = keycloak.tokenParsed.sub || "";
                newCoach.email = keycloak.tokenParsed.email || "";
                newCoach.nom = keycloak.tokenParsed.family_name || "";
                newCoach.prenom = keycloak.tokenParsed.given_name || "";
                const response = await coachService.create(newCoach.toDTO());
                const coach = new Coach(response.data);
                return coach;

            }
            else if(roles.includes("athlete")){
                const newAthlete: Athlete = new Athlete();
                newAthlete.keycloakId = keycloak.tokenParsed.sub || "";
                newAthlete.email = keycloak.tokenParsed.email || "";
                newAthlete.nom = keycloak.tokenParsed.family_name || "";
                newAthlete.prenom = keycloak.tokenParsed.given_name || "";
                const response = await athleteService.create(newAthlete.toDTO());
                const athlete = new Athlete(response.data);
                return athlete;
            }
                else console.error("Error : role inconnu");
            }
            else console.error("Error : role null");
        }
        else console.error("Error : token Keylcoak null");
        console.error("Error : pendant la récupération de l'User");
        return null;
    }
    catch (error) {
        console.error("Error fetching user:", error);
        return null;
    }   
}

export async function getSessionOfActivite(session:Session):Promise<Activite[]|null>{
    try {
        if(session.id !=null){
            const activites:Activite[] = [];
            const response = await sessionService.getActivities(session.id!);
            response.data.forEach(activiteDTO => {
                activites.push(new Activite(activiteDTO));
            });
            return activites;
        }
        return null;
    } catch (error) {
        console.error("Error getting session:", error);
        return null;
    }
}


export async function deletActiviteFromSession(activite:Activite){
    try {
        if(activite.id !=null){
         activiteService.delete(activite.id);
        }
    } catch (error) {
        console.error("Error getting session:", error);
    }
}

export async function addActiviteToSession(session:Session,activite:Activite):Promise<Boolean>{
    try {
        if(activite.id !=null && session.id !=null){
            await sessionService.addActivity(session.id,activite.id)
            return true;

        }
        return false
    } catch (error) {
        console.error("Error getting session:", error);
        return false;
    }
}

export async function updateActivitiesOfSessionAPI(session:Session){
    try {
        session.activites.forEach(activite => {
            if(activite.id!=null){
                activiteService.update(activite.id, activite.toDTO());
            }
        });
        // To refresh the activities in the session object
        //const response = await sessionService.getActivities(session_id!);
        //session.activites = response.data;
    } catch (error) {
        console.error("Error fetching activities for session:", error);
    }
}

export async function subscribeSessionAPI(user:User, session:Session):Promise<boolean>{
    try {
        const session_id =session.id
        const user_id = user.id
        const response = await sessionService.subscribe(session_id!, user_id!);
        return true;
    } catch (error) {
        console.error("Error subscribing to session:", error);
        return false;
    }
}

export async function unsubscribeSessionAPI(user:Athlete, session:Session):Promise<boolean>{
    try {
        const session_id =session.id
        const user_id = user.id
        const response = await sessionService.unsubscribe(session_id!, user_id!);
        return true;
    } catch (error) {
        console.error("Error unsubscribing from session:", error);
        return false;
    }
}



// POST /////////////////////////////////////////////////////////

// COACH ADMIN 
export async function createSessionAPI(session: Session): Promise<Session> {
    async function postActivite(activite:Activite,sessionRes:Session){
        activite.session = sessionRes;
        const activite2 = await createActivityAPI(activite);
        activite2.session = sessionRes;
        sessionRes.activites.push(activite2);
    }

    try {
        const response = await api.post<SessionDTO>("/session/create", session.toDTO());
        const sessionRes:Session = new Session(response.data);
        await Promise.all(
            session.activites.map(activite =>
                postActivite(activite, sessionRes)
            )
        );
        console.log(sessionRes.activites);
        updateActivitiesOfSessionAPI(sessionRes);

        return sessionRes;
    } catch (error) {
        console.error("Error creating session:", error);
        throw error;
    }
}


export async function createActivityAPI(activity: Activite):Promise<Activite>{
    try {
        const response = await activiteService.create(activity.toDTO())
        return new Activite(response.data);
    } catch (error) {
        console.error("Error creating activity:", error);
        throw error;
    }
}

export async function getAllActiviteAPI(): Promise<Activite[]> {
    try {
        const response = await activiteService.getAll();
        const activites:Activite[] = []
        response.data.forEach(dto => {
            activites.push(new Activite(dto));
        });
        return activites;
    } catch (error) {
        console.error("Error fetching users:", error);
        throw error;
    }
}


export async function postAthlete(athlete: Athlete):Promise<Athlete>{
   try {
        const response = await api.post<Athlete>("/athlete/create/",athlete.toDTO);
        console.log(response);
        return response.data;
    } catch (error) {
        console.error("Error fetching coachs:", error);
        throw error;
    }
}

export async function postSession(session: Session){
    try {
       /* const data = {
                name: session.name,
                creneau: session.creneau, // string ISO OK
                duree: session.duree,
                isRecurrent: session.isRecurrent,

                coachId: session.coach?.id,
                groupe: session.groupe ? session.groupe  : undefined,
        }*/

        const response = await sessionService.create(session.toDTO());
        session.id = response.data.id; //TODO ?

        session.activites.forEach(activite => {
            const data2 = {
                name: activite.nom,
                duree: activite.duree,
                date: activite.data,
                theme: activite.theme,
                sessionId: session.id, //TODO
            }
            activiteService.create(data2);
            //     console.log("Session créée");
        });
    } catch (error) {
        console.error("Error post Session:", error);
        throw error;
    }
}

// SET /////////////////////////////////////////////////////////
export async function createAdminAPI(athlete: Admin):Promise<Admin>{
   try {
        const response = await api.post<Admin>("/admin/create/",athlete);
        console.log(response);
        return response.data;
    } catch (error) {
        console.error("Error fetching coachs:", error);
        throw error;
    }
}

//GET /////////////////////////////////////////////////////////

//USER 
export async function getAllUserAPI(): Promise<User[]> {
    try{
        const response = await api.get<User[]>("/users/all");
        return response.data;
    }catch (error) {
        console.error("Error fetching users:", error);
        throw error;
    }
}

export async function getCoachByIdAPI(id:number|null): Promise<Coach|null> {
    try{
        if(id!==null){
            const response = await coachService.getById(id);
            return new Coach(response.data);
        }
        console.error("Error fetching coach by id : id null");
        return null;
    }catch (error) {
        console.error("Error fetching coach by id:", error);
        return null;
    }
}

//SESSION
export async function getSessionsOfUserAPI(user:User): Promise<Session[]>{
    try {
        var sessionsDTO:SessionDTO[] = []
        if (user instanceof Coach) {
            const response = await coachService.getSessionsForCoach(user.id); //TODO
            sessionsDTO = response.data;
        }else if (user instanceof Athlete) {
            const response = await athleteService.getSessionsForAthlete(user.id); //TODO
            sessionsDTO = response.data;
        }
        const sessions:Session[] = [];
        sessionsDTO.forEach(sessionDTO => {
            sessions.push(new Session(sessionDTO));
        });
        return sessions;

    }catch (error) {
        console.error("Error fetching sessions for user:", error);
        return [];
    }
}

export async function getAllSessionsAPI():Promise<Session[]>{
    try {
        const response = await sessionService.getAll();
        const sessions = await Promise.all(
            response.data.map(async sessionDTO => {
                const session = new Session(sessionDTO);
                const coach = await getCoachByIdAPI(sessionDTO.coachId);

                if (coach != null) {
                    session.coach = coach;
                }
                return session;
            })
        );

        return sessions;
    } catch (error) {
        console.error("Error fetching sessions:", error);
        throw error;
    }
}


function formatDateLocal(date: Date): string {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, "0");
  const day = String(date.getDate()).padStart(2, "0");

  return `${year}-${month}-${day}`;
}


export async function getAllSessionsBetweenAPI(d1:Date,d2:Date):Promise<Session[]>{
    try {
        const data = {
            startDate: formatDateLocal(d1),
            endDate: formatDateLocal(d2)
        }
        console.log(d1 + " " + d2);
        console.log(data);
        const response = await sessionService.getAllBetweenDate(data);
        const sessions = await Promise.all(
            response.data.map(async sessionDTO => {
                const session = new Session(sessionDTO);
                const coach = await getCoachByIdAPI(sessionDTO.coachId);

                if (coach != null) {
                    session.coach = coach;
                }
                return session;
            })
        );

        return sessions;
    } catch (error) {
        console.error("Error fetching sessions:", error);
        throw error;
    }
}

//COACH
export async function getAllCoach(): Promise<Coach[]> {
    try {
        const response = await coachService.getAll();
        const coachs:Coach[] = []
        response.data.forEach(dto => {
            coachs.push(new Coach(dto));
        });
        return coachs;
    } catch (error) {
        console.error("Error fetching coachs:", error);
        throw error;
    }
}

//ATHLETE
export async function getAllAthlete(): Promise<Athlete[]> {
    try {
        const response = await athleteService.getAll();
        const athletes:Athlete[] = []
        response.data.forEach(dto => {
            athletes.push(new Athlete(dto));
        });
        return athletes;
    } catch (error) {
        console.error("Error fetching users:", error);
        throw error;
    }
}

