use std::time::Duration;

use tab_api::tab::normalize_name;
use tokio::time;

use crate::{
    message::main::MainRecv, message::main::MainShutdown, prelude::*, state::tabs::ActiveTabsState,
    utils::await_state,
};

pub struct MainCloseTabsService {
    _run: Lifeline,
}

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

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

        let mut tx_request = bus.tx::<Request>()?;
        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::CloseTabs(tabs) = msg {
                    let state = await_state(&mut rx_active).await?;
                    let exit_code = Self::close_tabs(tabs, state, &mut tx_request).await?;

                    time::delay_for(Duration::from_millis(5)).await;
                    tx_shutdown.send(MainShutdown(exit_code)).await?;
                    break;
                }
            }

            Ok(())
        });

        Ok(Self { _run })
    }
}

impl MainCloseTabsService {
    async fn close_tabs(
        tabs: Vec<String>,
        state: ActiveTabsState,
        tx_websocket: &mut impl Sender<Request>,
    ) -> anyhow::Result<i32> {
        if tabs.is_empty() {
            if let Ok(tab) = std::env::var("TAB_ID") {
                eprintln!(
                    "Closing current tab: {}",
                    std::env::var("TAB").unwrap_or("".to_string())
                );

                let id = tab.parse()?;
                tx_websocket.send(Request::CloseTab(id)).await?;
            } else {
                eprintln!("No arguments or current tab were detected.");
                return Ok(1);
            }

            return Ok(0);
        }

        let running_tabs = state.into_name_set();

        for tab in tabs {
            let name = normalize_name(tab.as_str());

            if !running_tabs.contains(&name) {
                eprintln!("Tab not running: {}", name);
                continue;
            }

            eprintln!("Closing tab: {}", name);

            let tab = state.find_name(name.as_str()).unwrap();
            tx_websocket.send(Request::CloseTab(tab.id)).await?;
        }

        Ok(0)
    }
}
