use crate::{
    message::main::MainRecv, message::main::MainShutdown, prelude::*,
    state::workspace::WorkspaceState, state::workspace::WorkspaceTab, utils::await_state,
};
use std::env;
use std::io::stdout;
use std::path::PathBuf;

use crossterm::{
    execute,
    style::{Color, Print, ResetColor, SetForegroundColor},
};

pub struct MainListTabsService {
    _run: Lifeline,
}

impl Service for MainListTabsService {
    type Bus = MainBus;
    type Lifeline = anyhow::Result<Self>;

    fn spawn(bus: &Self::Bus) -> Self::Lifeline {
        let mut rx = bus.rx::<MainRecv>()?;
        let mut rx_workspace = bus.rx::<Option<WorkspaceState>>()?.into_inner();

        let mut tx_shutdown = bus.tx::<MainShutdown>()?;

        let _run = Self::try_task("run", async move {
            while let Some(msg) = rx.recv().await {
                if let MainRecv::ListTabs = msg {
                    let workspace = await_state(&mut rx_workspace).await?;

                    if workspace.errors.len() > 0 {
                        eprintln!("Workspace errors were found during startup.  Use `tab --check` for more details.");
                        eprintln!("");
                    }

                    Self::echo_tabs(&workspace.tabs);
                    tx_shutdown.send(MainShutdown(0)).await.ok();
                    break;
                }
            }

            Ok(())
        });

        Ok(Self { _run })
    }
}

impl MainListTabsService {
    fn echo_tabs(tabs: &Vec<WorkspaceTab>) {
        debug!("echo tabs: {:?}", &tabs);

        if tabs.len() == 0 {
            println!("No active tabs.");
            return;
        }

        let len = tabs.iter().map(|tab| tab.name.len()).max().unwrap();
        let target_len = len + 4;

        println!("Available tabs:");
        let cwd: PathBuf = env::current_dir().unwrap_or_default();

        for tab in tabs.iter() {
            let name = &tab.name;
            print!("    ");

            if *name == get_working_tab() {
                color_active_tabs(name, Color::Yellow)
            } else if is_active(tab, &cwd) {
                color_active_tabs(name, Color::Blue)
            } else {
                print!("{}", name);
            }

            if let Some(ref doc) = tab.doc {
                for _ in name.len()..target_len {
                    print!(" ");
                }
                println!("({})", doc);
            } else {
                println!("");
            }
        }
    }
}

fn is_active(tab: &WorkspaceTab, cwd: &PathBuf) -> bool {
    cwd.starts_with(tab.directory.as_path())
}

fn color_active_tabs(name: &str, color: Color) {
    execute!(stdout(), SetForegroundColor(color), Print(name), ResetColor).ok();
}

fn get_working_tab() -> String {
    env::var_os("TAB")
        .unwrap_or_default()
        .to_str()
        .unwrap_or_default()
        .to_string()
}
