use log::error;
use serde::{Deserialize, Serialize};

use crate::db;

#[derive(Serialize, Clone)]
pub struct Person {
    /// Internal id
    pub person_id: i32,
    /// Country-specific id. For now only supports Peru's DNI.
    ///
    /// Example: `74185293`
    pub person_dni: String,
    /// Names
    ///
    /// Example: `Juan Carlos`
    pub person_names: String,
    /// First surname
    ///
    /// Example: `Perez`
    pub person_paternal_surname: String,
    /// Second surname
    ///
    /// Example: `Gomez`
    pub person_maternal_surname: String,
    /// Id of the online classroom user id linked to this user
    pub person_classroom_id: Option<i32>,
    pub person_classroom_username: Option<String>,
}

impl Person {
    pub async fn get_by_dni(dni: i32) -> Result<Person, sqlx::Error> {
        let db = db();

        let result = sqlx::query_as!(Person, "SELECT * FROM person WHERE person_dni = ?", dni)
            .fetch_one(db)
            .await;

        match result {
            Ok(v) => Ok(v),
            Err(e) => {
                error!("Error searching person with dni {}: {:?}", dni, e);
                Err(e)
            }
        }
    }
}

#[derive(Deserialize)]
pub struct PersonCreate {
    pub person_dni: String,
    pub person_names: String,
    pub person_paternal_surname: String,
    pub person_maternal_surname: String,
}

impl PersonCreate {
    pub async fn create(&self) -> Result<(), sqlx::Error> {
        let db = db();

        sqlx::query!(
            "INSERT INTO person (person_dni, person_names, person_paternal_surname, person_maternal_surname) VALUES (?, ?, ?, ?)", 
            self.person_dni,
            self.person_names,
            self.person_paternal_surname,
            self.person_maternal_surname,
        )
            .execute(db)
            .await?;

        Ok(())
    }
}

#[derive(Serialize, Deserialize)]
pub struct PersonLink {
    pub person_id: i32,
    pub person_classroom_id: i32,
    pub person_classroom_username: String,
}

impl PersonLink {
    pub async fn insert(&self) -> Result<(), String> {
        let db = db();

        let res = sqlx::query!(
            "UPDATE person SET person_classroom_id = ?, person_classroom_username = ? WHERE person_id = ?",
            self.person_classroom_id,
            self.person_classroom_username,
            self.person_id,
        )
        .execute(db)
        .await;

        match res {
            Ok(_) => Ok(()),
            Err(error) => {
                eprintln!("Error linking person to classroom: {:?}", error);
                Err(format!("Error vinculando persona."))
            }
        }
    }
}
