use crate::json_result::JsonResult;

use super::session::request;
use rocket::{http::Status, serde::json::Json};
use scraper::{ElementRef, Html, Selector};
use serde::{Deserialize, Serialize};
use urlencoding::encode;

#[derive(Debug, Serialize, Deserialize)]
pub struct ClassroomPerson {
    name: String,
    surname: String,
    username: String,
    user_id: String,
}

// Instead of requesting pages and managing session & cookies manually,
// create a wrapper that:
// - Checks if the session cookie is valid
//   - If not, tries to login
// - Makes the request
// - Returns the html string, or an error

#[get("/classroom/users/<full_name>")]
pub async fn get_users(full_name: String) -> (Status, Json<JsonResult<Vec<ClassroomPerson>>>) {
    let html = request(format!(
        "/main/admin/user_list.php?keyword={}&submit=&_qf__search_simple=",
        encode(full_name.as_str())
    ))
    .await;

    match html {
        Ok(html) => match parse_users(&html) {
            Ok(users) => (Status::Ok, JsonResult::ok(users)),
            Err(reason) => {
                // println!("{}", html);
                (Status::InternalServerError, JsonResult::err(reason))
            }
        },
        Err(reason) => (Status::InternalServerError, JsonResult::err(reason)),
    }
}

fn parse_users(file: &str) -> Result<Vec<ClassroomPerson>, String> {
    // Selectors
    let Ok(form_selector) = Selector::parse("form#form_users_id") else {
        return Err("Error parsing form#form_users_id selector".into());
    };
    let Ok(tr_selector) = Selector::parse("tr:not(:first-child)") else {
        return Err("Error parsing tr:not(:first-child) selector".into());
    };
    let Ok(td_selector) = Selector::parse("td") else {
        return Err("Error parsing td selector".into());
    };

    let fragment = Html::parse_document(file);

    let form_element = match fragment.select(&form_selector).next() {
        Some(el) => el,
        // If the form is not found, it may mean that no users were found
        None => {
            let Ok(secondary_button) = Selector::parse("#img_plus_and_minus") else {
                return Err("Error parsing secondary button selector".into());
            };

            match fragment.select(&secondary_button).next() {
                Some(_) => return Ok(Vec::new()),
                None => return Err("Error parsing html: no form or empty form found.".into()),
            }
        }
    };

    let mut result_vec = Vec::new();
    for element in form_element.select(&tr_selector) {
        let td_vec: Vec<_> = element.select(&td_selector).collect();

        if td_vec.len() != 12 {
            return Err(format!(
                "Error parsing tr: td elements count is not 12, but {}",
                td_vec.len()
            ));
        }

        result_vec.push(get_person_data(&td_vec)?);
    }

    Ok(result_vec)
}

fn get_person_data(td_vec: &Vec<ElementRef>) -> Result<ClassroomPerson, String> {
    // Surnames
    let surname_ref = td_vec[3];
    let name_ref = td_vec[4];
    let username_ref = td_vec[5];

    // Selectors
    let a_selector = Selector::parse("a").expect("Error parsing `a` selector");

    //
    // Get the href of the surname link
    //
    let surnames_a_node = surname_ref
        .first_child()
        .ok_or("Expected the 3rd td element to have a children")?;

    let surnames_a_element = surnames_a_node
        .value()
        .as_element()
        .ok_or("Expected the 3rd td element to have an html children")?;

    let href_value = surnames_a_element
        .attr("href")
        .ok_or("Expected the 3rd td element's children to have an href attribute")?;

    // Get the surname
    let Some(surname_a_element) = surname_ref.select(&a_selector).next() else {
        return Err("Expected the 3rd td element to have an `a` element".into());
    };
    let surname = surname_a_element.inner_html();

    // Get the name
    let Some(surnames_a_element) = name_ref.select(&a_selector).next() else {
        return Err("Expected the 4th td element to have an `a` element".into());
    };
    let name = surnames_a_element.inner_html();

    // Get the username
    let username = username_ref.inner_html();

    // Parse userid from href
    // format: https://testing.aulavirtual.eegsac.com/main/admin/user_information.php?user_id=1087
    // Get the position of 'user_id='
    let user_id_start = href_value.find("user_id=").ok_or("Error parsing user_id")? + 8;
    let user_id = href_value[user_id_start..].to_string();

    Ok(ClassroomPerson {
        name,
        surname,
        username,
        user_id,
    })
}
