use chrono::{Duration, NaiveDate};

use reqwest::Result;

use serde::de::DeserializeOwned;

use crate::ncaa::common::BASE_URL;


// TODO: add example here in the doc string
pub async fn live_today<T: DeserializeOwned>() -> Result<T> {
    let request_url = format!("{}/casablanca/live-today.json", BASE_URL);
    println!("{:#?}", request_url);
    let response: T = reqwest::Client::new()
        .get(request_url)
        .send().await?
        .json().await?;
    Ok(response)
}

// TODO: add example here in the doc string
pub async fn scoreboard<T: DeserializeOwned + Default>(sport: &str, division: &str, date: &str) -> Result<T> {
    let request_url = format!("{}/casablanca/scoreboard/{}/{}/{}/scoreboard.json", BASE_URL, sport, division, date);
    println!("{:#?}", request_url);
    let response: reqwest::Response = reqwest::Client::new()
        .get(request_url)
        .send().await?;
    if response.status() != reqwest::StatusCode::OK {
        Ok(T::default())
    } else {
        Ok(response.json().await?)
    }
}

// TODO: add example here in the doc string
pub async fn game_info<T: DeserializeOwned>(game: &str) -> Result<T> {
    let request_url = format!("{}/casablanca/game/{}/gameInfo.json", BASE_URL, game);
    println!("{:#?}", request_url);
    let response: T = reqwest::Client::new()
        .get(request_url)
        .send().await?
        .json().await?;
    Ok(response)
}

// TODO: add example here in the doc string
pub async fn scoring_summary<T: DeserializeOwned>(game: &str) -> Result<T> {
    let request_url = format!("{}/casablanca/game/{}/scoringSummary.json", BASE_URL, game);
    println!("{:#?}", request_url);
    let response: T = reqwest::Client::new()
        .get(request_url)
        .send().await?
        .json().await?;
    Ok(response)
}

/// Query the scoreboards for every day between given dates
/// Return them as a vector of Scoreboards
pub async fn scoreboards_between<T: DeserializeOwned + Default>(
    sport: &str,
    division: &str,
    date_fmt: &str,
    start_date: &str,
    end_date: &str) -> Result<Vec<T>> {
        let start = NaiveDate::parse_from_str(start_date, date_fmt).unwrap();
        let end = NaiveDate::parse_from_str(end_date, date_fmt).unwrap();
        let mut dt = start;
        let mut vec_scoreboards = Vec::<T>::new();
        while dt <= end {
            let result = scoreboard(sport, division, &dt.format(date_fmt).to_string()).await?;
            vec_scoreboards.push(result);
            dt = dt + Duration::days(1);
        }
    
        Ok(vec_scoreboards)
}

// TODO: add example here in the doc string
pub async fn boxscore<T: DeserializeOwned>(game: &str) -> Result<T> {
    let request_url = format!("{}/casablanca/game/{}/boxscore.json", BASE_URL, game);
    println!("{:#?}", request_url);
    let response: T = reqwest::Client::new()
        .get(request_url)
        .send().await?
        .json().await?;
    Ok(response)
}

// TODO: add example here in the doc string
pub async fn play_by_play<T: DeserializeOwned>(game: &str) -> Result<T> {
    let request_url = format!("{}/casablanca/game/{}/pbp.json", BASE_URL, game);
    println!("{:#?}", request_url);
    let response: T = reqwest::Client::new()
        .get(request_url)
        .send().await?
        .json().await?;
    Ok(response)
}
