use std::str::FromStr;

use crate::GameState;
use crate::fleet::FleetsManager;
use crate::solar_system::body::{BodyId, OrbitalBody};
use crate::solar_system::{Kilometers, SolarSystem, SystemId};
use crate::ui::contact::MapContact;

pub struct FleetsListWidget<'f>
{
    fleets_man: &'f FleetsManager,
    selected: &'f mut Option<MapContact>,
}

pub struct FleetsListResponse
{
    pub response: egui::Response,
    pub refocus: Option<(SystemId, MapContact)>
}

pub struct FleetsControlPanel
{
    new_fleet_modal: Option<NewFleetModal>
}

pub struct FleetsControlResponse
{
    pub new_fleet: Option<NewFleetModal>
}

#[derive(Clone)]
pub struct NewFleetModal
{
    pub name: String,
    pub sma: Kilometers,
}

impl<'f> FleetsListWidget<'f>
{
    pub fn new(
        fleets_man: &'f FleetsManager,
        selected: &'f mut Option<MapContact>)
    -> Self
    {
        Self {
            fleets_man,
            selected
        }
    }

    pub fn show_ui(
        mut self,
        ui: &mut egui::Ui)
    -> FleetsListResponse
    {
        let frame_resp = egui::Frame::new()
            .fill(egui::Color32::from_gray(48))
            .outer_margin(egui::Margin::same(4))
            .inner_margin(egui::Margin::same(4))
            .show(ui, 
        |frame| {
            frame.set_max_height(frame.available_height() / 2.0);
            self.show_fleets_list(frame)
        });

        FleetsListResponse {
            response: frame_resp.response,
            refocus: frame_resp.inner
        }
    }

    fn show_fleets_list(
        &mut self,
        ui: &mut egui::Ui)
    -> Option<(SystemId, MapContact)>
    {
        egui::ScrollArea::vertical()
            .auto_shrink(false)
            .show(ui, 
        |scrollarea| {
            let mut refocus: Option<(SystemId, MapContact)> = None;
            for id in self.fleets_man.all() {
                let fleet = match self.fleets_man.fleet(id) {
                    Some(v) => v,
                    None => { continue; }
                };
                let contact = MapContact::from_fleet(id);
                let selected = self.selected.is_some_and(|v| { v == contact });
                let resp = scrollarea.selectable_label(selected, fleet.name());

                if resp.double_clicked() {
                    refocus = Some((fleet.system(), contact));
                }else if resp.clicked() {
                    *self.selected = if selected { None } else { Some(contact) };
                }
            }
            refocus
        }).inner
    }
} // impl FleetsListWidget

impl FleetsControlPanel
{
    pub fn show(
        &mut self,
        selected_contact: &Option<MapContact>,
        fleets_man: &FleetsManager,
        star_system: &SolarSystem,
        ui: &mut egui::Ui)
    -> FleetsControlResponse
    {
        let mut response = FleetsControlResponse {
            new_fleet: None
        };

        egui::Frame::new()
            .inner_margin(egui::Margin::same(4))
            .outer_margin(egui::Margin::same(4))
            .fill(egui::Color32::from_gray(48))
            .show(ui, 
        |frame| {
            frame.horizontal(|horizontal| {
                horizontal.take_available_width();
                if horizontal.button("New Fleet").clicked() {
                    self.new_fleet_modal = Some(NewFleetModal::default());
                }
            });
        });

        if let Some(new_fleet_modal) = &mut self.new_fleet_modal {
            let modal = new_fleet_modal.show(
                selected_contact,
                fleets_man,
                star_system,
                ui.ctx());
            
            if modal.inner {
                response.new_fleet = self.new_fleet_modal.take();
            }

            if modal.should_close() {
                self.new_fleet_modal = None;
            }
        }

        response
    }
}

impl Default for FleetsControlPanel
{
    fn default() 
    -> Self 
    {
        Self {
            new_fleet_modal: None
        }
    }
}

impl NewFleetModal
{
    pub fn show(
        &mut self,
        selected_contact: &Option<MapContact>,
        fleets_man: &FleetsManager,
        star_system: &SolarSystem,
        ctx: &egui::Context)
    -> egui::ModalResponse<bool>
    {
        let sma_min = match selected_contact.unwrap_or(MapContact::from_body(0)).body() {
            Some(id) => star_system.body(id).radius(),
            None => 0.0
        };

        egui::Modal::new(egui::Id::new("NewFleetModal")).show(ctx, |ui| {
            ui.set_width(256.0);
            ui.heading("Create new debug fleet");
            
            ui.horizontal(|ui| {
                ui.label("Name: ");
                ui.text_edit_singleline(&mut self.name);
            });
            
            ui.horizontal(|ui| {
                ui.label("Orbiting: ");
                ui.label(selected_contact.unwrap_or(MapContact::from_body(0)).name(star_system, fleets_man));
                ui.label(" above ");
                ui.add(
                    egui::DragValue::new(&mut self.sma).range(sma_min..=f32::MAX).suffix("km")
                );
            });

            if ui.button("Create").clicked() {
                ui.close();
                return true;
            }
            false
        })
    }
}

impl Default for NewFleetModal
{
    fn default()
    -> Self
    {
        Self {
            name: String::from_str("New Fleet").unwrap(),
            sma: 0.0
        }
    }
}

impl GameState
{
    pub fn new_fleet_from_modal(
        &mut self,
        modal: NewFleetModal,
        star_system: SystemId,
        contact: Option<MapContact>)
    {
        let contact = contact.unwrap_or(MapContact::from_body(0));
        let star_system = &self.solar_systems[star_system];
        let body = match contact.body() {
            Some(id) => id,
            None => 0
        };
        self.fleets.new_fleet_from_modal(modal, star_system, body);
    }
}

impl FleetsManager
{
    pub fn new_fleet_from_modal(
        &mut self,
        modal: NewFleetModal,
        star_system: &SolarSystem,
        body: BodyId)
    {
        let id = self.new_fleet(modal.name, star_system.id());
        let fleet = self.fleet_mut(id).unwrap();

        fleet.make_orbit(star_system, body, modal.sma);
    }
}
