use super::main;
use crate::testing::{report_results, test_view, test_view_change_sim, Size};

use inflorescence_iced_widget::report;
use inflorescence_model::model::{
    ManagingRepo, ManagingRepoSubState, ReadyState, State, SubMenu, SubState,
};
use inflorescence_model::{action, selection};
use libflorescence::identity::Id;
use libflorescence::prelude::*;
use libflorescence::{file, repo, PijulConfig};

use iced::window;

use std::collections::{BTreeMap, BTreeSet};
use std::path::PathBuf;
use std::str::FromStr;

const WINDOW_SIZE: iced::Size = iced::Size {
    width: 1024.0,
    height: 768.0,
};
const WINDOW_SCALE: f32 = 1.0;

#[test]
fn view_app() {
    let window_id = window::Id::unique();
    let size = Size::Fullscreen;
    let config = PijulConfig::default();

    let mut results = vec![];
    let mresults = &mut results;

    let view = |state| main(state, |_id| None, window_id);

    let to_file_path = |raw: &str| file::Path {
        raw: raw.to_string(),
        is_dir: false,
    };
    let to_dir_path = |raw: &str| file::Path {
        raw: raw.to_string(),
        is_dir: true,
    };

    // _________________________________________________________________________
    //
    let uniq_name = "loading_repo";

    let sub = ManagingRepoSubState::Loading {
        user_ids: None,
        repo: None,
    };
    let report = report::Container::default();
    let repo_path = PathBuf::from("test/repo/path");
    let state = ManagingRepo {
        repo_path: repo_path.clone(),
        sub,
    };
    let sub = SubState::ManagingRepo(state);
    let mut state = State {
        sub,
        window_size: WINDOW_SIZE,
        window_scale: WINDOW_SCALE,
        allowed_actions: vec![],
        sub_menu: None,
        report,
    };
    action::update_allowed_actions(&mut state);

    test_view(mresults, uniq_name, view(&state), size);

    // _________________________________________________________________________
    //
    let uniq_name = "loaded_empty_repo";

    let repo = repo::State {
        dir_name: "path".to_string(),
        channel: "some_channel".to_string(),
        other_channels: BTreeSet::new(),
        untracked_files: BTreeSet::new(),
        changed_files: BTreeMap::new(),
        short_log: vec![],
        remotes: default(),
    };
    let ready_state = ReadyState {
        user_id: Id::default(&config).unwrap(),
        repo,
        selection: default(),
        navigation: default(),
        record_changes: default(),
        logs: default(),
        forking_channel_name: default(),
        to_record: default(),
        jobs: default(),
        record_dichotomy: default(),
    };
    let sub = ManagingRepoSubState::Ready(ready_state);
    let report = report::Container::default();
    let state = ManagingRepo {
        repo_path: repo_path.clone(),
        sub,
    };
    let sub = SubState::ManagingRepo(state);
    let mut state = State {
        sub,
        window_size: WINDOW_SIZE,
        window_scale: WINDOW_SCALE,
        allowed_actions: vec![],
        sub_menu: None,
        report,
    };
    action::update_allowed_actions(&mut state);

    test_view(mresults, uniq_name, view(&state), size);

    // _________________________________________________________________________
    //
    let uniq_name = "loaded_non_empty_repo";

    let repo = repo::State {
        dir_name: "path".to_string(),
        channel: "some_channel".to_string(),
        other_channels: BTreeSet::new(),
        untracked_files: BTreeSet::from_iter([
            to_file_path("untracked.rs"),
            to_dir_path("untracked_dir"),
            to_file_path("a/sub/dir/somewhere/deep/untracked_file.rs"),
        ]),
        changed_files: BTreeMap::from_iter([
            (to_file_path("changed_file.rs"), BTreeSet::default()),
            (
                to_file_path("a/sub/dir/somewhere/deep/changed_file.rs"),
                BTreeSet::default(),
            ),
        ]),
        short_log: vec![repo::LogEntry {
            hash: repo::ChangeHash::None,
            message: "the very last change".to_string(),
            description: None,
            timestamp: Timestamp::from_str("2024-03-10T06:05:00Z").unwrap(),
            file_paths: vec![],
        }],
        remotes: default(),
    };
    let ready_state = ReadyState {
        user_id: Id::default(&config).unwrap(),
        repo: repo.clone(),
        selection: default(),
        navigation: default(),
        record_changes: default(),
        logs: default(),
        forking_channel_name: default(),
        to_record: default(),
        jobs: default(),
        record_dichotomy: default(),
    };
    let sub = ManagingRepoSubState::Ready(ready_state);
    let report = report::Container::default();
    let state = ManagingRepo {
        repo_path: repo_path.clone(),
        sub,
    };
    let sub = SubState::ManagingRepo(state);
    let mut state = State {
        sub,
        window_size: WINDOW_SIZE,
        window_scale: WINDOW_SCALE,
        allowed_actions: vec![],
        sub_menu: None,
        report,
    };
    action::update_allowed_actions(&mut state);

    test_view(mresults, uniq_name, view(&state), size);

    // _________________________________________________________________________
    //
    let uniq_name = "loaded_point_at_untracked";

    test_view_change_sim(mresults, uniq_name, view(&state), size, |sim| {
        let target = sim.find("untracked.rs").unwrap();
        sim.point_at(target.bounds().center());
    });

    // _________________________________________________________________________
    //
    let uniq_name = "loaded_selected_untracked";

    let status_selection = Some(selection::Status::UntrackedFile {
        ix: 0,
        path: to_file_path(""),
        diff_selected: false,
    });
    let ready_state = ReadyState {
        user_id: Id::default(&config).unwrap(),
        repo,
        selection: selection::State {
            status: status_selection,
            ..default()
        },
        navigation: default(),
        record_changes: default(),
        logs: default(),
        forking_channel_name: default(),
        to_record: default(),
        jobs: default(),
        record_dichotomy: default(),
    };
    let sub = ManagingRepoSubState::Ready(ready_state);
    let report = report::Container::default();
    let state = ManagingRepo {
        repo_path: repo_path.clone(),
        sub,
    };
    let sub = SubState::ManagingRepo(state);
    let mut state = State {
        sub,
        window_size: WINDOW_SIZE,
        window_scale: WINDOW_SCALE,
        allowed_actions: vec![],
        sub_menu: None,
        report,
    };
    action::update_allowed_actions(&mut state);
    test_view(mresults, uniq_name, view(&state), size);

    // _________________________________________________________________________
    //
    let uniq_name = "loaded_shown_reports";

    let repo = repo::State {
        dir_name: "path".to_string(),
        channel: "some_channel".to_string(),
        other_channels: BTreeSet::new(),
        untracked_files: BTreeSet::new(),
        changed_files: BTreeMap::new(),
        short_log: vec![],
        remotes: default(),
    };
    let ready_state = ReadyState {
        user_id: Id::default(&config).unwrap(),
        repo,
        selection: default(),
        navigation: default(),
        record_changes: default(),
        logs: default(),
        forking_channel_name: default(),
        to_record: default(),
        jobs: default(),
        record_dichotomy: default(),
    };
    let repo_path = PathBuf::from("test/repo/path");
    let sub = ManagingRepoSubState::Ready(ready_state);
    let report = report::Container {
        hidden: false,
        entries: vec![
            report::Entry {
                level: report::Level::Info,
                msg: "Sed a rhoncus elit. Vestibulum molestie lacus blandit eleifend auctor. Nulla eget fermentum erat. Suspendisse quis erat faucibus enim facilisis cursus.".to_string(),
                time: Timestamp::from_str("2024-03-10T06:05:00Z").unwrap(),
                is_read: false,
            },
            report::Entry {
                level: report::Level::Warning,
                msg: "Morbi at justo".to_string(),
                time: Timestamp::from_str("2024-03-10T06:04:33Z").unwrap(),
                is_read: false,
            },
            report::Entry {
                level: report::Level::Error,
                msg: "Curabitur sit amet nisl venenatis, suscipit magna at, elementum dolor".to_string(),
                time: Timestamp::from_str("2024-03-10T06:02:10Z").unwrap(),
                is_read: true,
            },
            report::Entry {
                level: report::Level::Warning,
                msg: "Aliquam lobortis egestas diam, a luctus dui imperdiet vitae".to_string(),
                time: Timestamp::from_str("2024-03-10T06:00:00Z").unwrap(),
                is_read: true,
            },
        ],
    };
    let state = ManagingRepo {
        repo_path: repo_path.clone(),
        sub,
    };
    let sub = SubState::ManagingRepo(state);
    let mut state = State {
        sub,
        window_size: WINDOW_SIZE,
        window_scale: WINDOW_SCALE,
        allowed_actions: vec![],
        sub_menu: None,
        report,
    };
    action::update_allowed_actions(&mut state);

    test_view(mresults, uniq_name, view(&state), size);

    // _________________________________________________________________________
    //
    let uniq_name = "sub_menu_push";

    let repo = repo::State {
        dir_name: "path".to_string(),
        channel: "some_channel".to_string(),
        other_channels: BTreeSet::new(),
        untracked_files: BTreeSet::new(),
        changed_files: BTreeMap::new(),
        short_log: vec![],
        remotes: default(),
    };
    let ready_state = ReadyState {
        user_id: Id::default(&config).unwrap(),
        repo,
        selection: default(),
        navigation: default(),
        record_changes: default(),
        logs: default(),
        forking_channel_name: default(),
        to_record: default(),
        jobs: default(),
        record_dichotomy: default(),
    };
    let repo_path = PathBuf::from("test/repo/path");
    let sub = ManagingRepoSubState::Ready(ready_state);
    let report = report::Container::default();
    let sub_menu = Some(SubMenu::Push {
        remote: None,
        opt: None,
    });
    let state = ManagingRepo {
        repo_path: repo_path.clone(),
        sub,
    };
    let sub = SubState::ManagingRepo(state);
    let mut state = State {
        sub,
        window_size: WINDOW_SIZE,
        window_scale: WINDOW_SCALE,
        allowed_actions: vec![],
        sub_menu,
        report,
    };
    action::update_allowed_actions(&mut state);

    test_view(mresults, uniq_name, view(&state), size);

    // _________________________________________________________________________
    //
    report_results(results);
}