use chrono::{DateTime, NaiveDate, NaiveTime, Utc};
use syrac_score::{
    flight::Flight,
    score::{score_flight_on_task, TaskResult},
    task::Task,
    turnpoint::TurnpointRole,
};

fn utc(date: NaiveDate, h: u32, m: u32, s: u32) -> DateTime<Utc> {
    date.and_time(NaiveTime::from_hms_opt(h, m, s).unwrap())
        .and_utc()
}

#[test]
fn test_score_flight_on_track() {
    let flight =
        Flight::from_igc_contents(include_str!("../data/2024-pwca-monroe-t3-33.igc")).unwrap();
    let task =
        Task::from_xctsk_contents(include_str!("../data/2024-pwca-monroe-t3.xctsk")).unwrap();
    let result = score_flight_on_task(&task, &flight);
    assert_eq!(flight.date, NaiveDate::from_ymd_opt(2024, 9, 12).unwrap());
    assert_eq!(result.total_seconds(&task).unwrap(), 6027);
    match result {
        TaskResult::NotCompleted => panic!(),
        TaskResult::Completed(attempt) => {
            let tag_times = attempt
                .tags
                .iter()
                .map(|tag| tag.pos.time)
                .collect::<Vec<_>>();
            assert_eq!(
                tag_times,
                vec![
                    utc(flight.date, 19, 45, 12),
                    utc(flight.date, 19, 51, 01),
                    utc(flight.date, 20, 21, 00),
                    utc(flight.date, 20, 53, 34),
                    utc(flight.date, 21, 17, 33),
                    utc(flight.date, 21, 25, 39),
                    utc(flight.date, 21, 28, 19),
                ]
            );
        }
    }
}

#[test]
fn test_score_utc_date_wraparound() {
    let flight =
        Flight::from_igc_contents(include_str!("../data/utc-date-wraparound.igc")).unwrap();
    let task =
        Task::from_xctsk_contents(include_str!("../data/utc-date-wraparound.xctsk")).unwrap();
    let result = score_flight_on_task(&task, &flight);
    assert_eq!(result.total_seconds(&task).unwrap(), 371);
    assert_eq!(flight.date, NaiveDate::from_ymd_opt(2024, 6, 5).unwrap());
    match result {
        TaskResult::NotCompleted => panic!(),
        TaskResult::Completed(attempt) => {
            let tag_times = attempt
                .tags
                .iter()
                .map(|tag| tag.pos.time)
                .collect::<Vec<_>>();
            assert_eq!(
                tag_times,
                vec![
                    utc(flight.date, 23, 55, 35),
                    utc(flight.date, 23, 57, 53),
                    utc(flight.date.succ_opt().unwrap(), 00, 01, 46),
                    utc(flight.date.succ_opt().unwrap(), 00, 04, 33),
                ]
            );
        }
    }
}

#[test]
fn test_pre_sss_turnpoints() {
    let flight =
        Flight::from_igc_contents(include_str!("../data/2024-pwca-monroe-t3-33.igc")).unwrap();
    let mut task =
        Task::from_xctsk_contents(include_str!("../data/2024-pwca-monroe-t3.xctsk")).unwrap();

    task.turnpoints[1].role = TurnpointRole::Turnpoint;
    task.turnpoints[2].role = TurnpointRole::Sss;

    let result = score_flight_on_task(&task, &flight);
    assert_eq!(flight.date, NaiveDate::from_ymd_opt(2024, 9, 12).unwrap());
    assert_eq!(result.total_seconds(&task).unwrap(), 5671);
    match result {
        TaskResult::NotCompleted => panic!(),
        TaskResult::Completed(attempt) => {
            let tag_times = attempt
                .tags
                .iter()
                .map(|tag| tag.pos.time)
                .collect::<Vec<_>>();
            assert_eq!(
                tag_times,
                vec![
                    // Tags are equivalent to those of the original task, except for
                    // the first (pre-SSS) turnpoint, which is tagged sooner because
                    // it does not influence speed section time.
                    utc(flight.date, 19, 36, 11),
                    // And the SSS is now tagged when exiting the turnpoint, 7 seconds
                    // after tagging it in the original task.
                    utc(flight.date, 19, 51, 08),
                    utc(flight.date, 20, 21, 00),
                    utc(flight.date, 20, 53, 34),
                    utc(flight.date, 21, 17, 33),
                    utc(flight.date, 21, 25, 39),
                    utc(flight.date, 21, 28, 19),
                ]
            );
        }
    }
}
