use crate::{consts, core::event_bus::EventBus, data::hazard_def::HazardType};
use godot::prelude::*;

#[derive(GodotClass)]
#[class(base=Node)]
pub struct BenchPressSystem {
    #[export]
    power_per_click: f32,
    #[export]
    gravity: f32,
    #[export]
    target_value: f32,

    current_progress: f32,
    is_lift_complete: bool,
    active_hazard_count: i32,
    event_bus: Option<Gd<EventBus>>,

    base: Base<Node>,
}

#[godot_api]
impl INode for BenchPressSystem {
    fn init(base: Base<Node>) -> Self {
        Self {
            power_per_click: 5.0,
            gravity: 2.0,
            target_value: 100.0,
            current_progress: 0.0,
            active_hazard_count: 0,
            is_lift_complete: false,
            event_bus: None,
            base,
        }
    }

    fn ready(&mut self) {
        let mut bus = self.base().get_node_as::<EventBus>(consts::EVENT_BUS_PATH);

        bus.connect(
            consts::LIFT_EFFORT_APPLIED,
            &self.base().callable("on_lift_effort"),
        );
        bus.connect(
            consts::HAZARD_SPAWNED,
            &self.base().callable("on_hazard_spawned"),
        );
        bus.connect(
            consts::HAZARD_RESOLVED,
            &self.base().callable("on_hazard_resolved"),
        );
        bus.connect(
            consts::LIFT_COMPLETED,
            &self.base().callable("on_lift_completed"),
        );

        self.event_bus = Some(bus);
    }

    fn process(&mut self, delta: f64) {
        if self.is_lift_complete {
            return;
        }

        let Some(bus) = &self.event_bus else {
            return;
        };
        let dt = delta as f32;

        if self.current_progress > 0.0 {
            self.current_progress -= self.gravity * dt;
            self.current_progress = self.current_progress.max(0.0);
        }

        let ratio = self.current_progress / self.target_value;
        bus.clone().bind_mut().publish_lift_progress(ratio);
        bus.clone().bind_mut().publish_lift_visual_height(ratio);
    }
}

#[godot_api]
impl BenchPressSystem {
    #[func]
    fn on_lift_effort(&mut self, delta: f32) {
        let Some(bus) = &mut self.event_bus else {
            return;
        };

        if self.is_lift_complete || self.active_hazard_count > 0 {
            return;
        }

        self.current_progress += self.power_per_click * delta;

        if self.current_progress >= self.target_value {
            self.is_lift_complete = true;
            bus.call_deferred("publish_lift_completed", &[true.to_variant()]);
        }
    }

    #[func]
    fn on_lift_completed(&mut self, _success: bool) {
        self.is_lift_complete = true;
    }

    #[func]
    fn on_hazard_spawned(&mut self, _type: HazardType) {
        self.active_hazard_count += 1;
    }

    #[func]
    fn on_hazard_resolved(&mut self, _type: HazardType) {
        self.active_hazard_count -= 1;
        if self.active_hazard_count < 0 {
            self.active_hazard_count = 0;
        }
    }
}
