use rand::rngs::ThreadRng;

use crate::mascot::MascotFrames;
use crate::mascot_fx::{self, DistanceMap};
use crate::wizard::WizardStep;
use crate::wizard::state::{StateResult, WizardAction, WizardState};
use crate::wizard::ui_controller::UiController;

use super::decode::Decode;

pub struct Entrance {
  tick: usize,
  distance_map: DistanceMap,
  steps: Vec<WizardStep>,
  step_idx: usize,
}

impl Entrance {
  pub fn new(mascot: MascotFrames, steps: Vec<WizardStep>, step_idx: usize) -> Self {
    let distance_map = mascot_fx::build_distance_map(mascot.lines());
    Self {
      tick: 0,
      distance_map,
      steps,
      step_idx,
    }
  }

  pub fn distance_map(&self) -> &DistanceMap {
    &self.distance_map
  }
}

impl WizardState for Entrance {
  fn tick(&mut self, ui: &mut UiController, _rng: &mut ThreadRng) -> StateResult {
    let progress = entrance_progress(&self.distance_map, self.tick);
    ui.mascot.entrance = progress;

    if mascot_fx::is_entrance_complete(&self.distance_map, self.tick) {
      ui.mascot.entrance = 1.0;
      ui.mascot.floating = true;
      let next = Decode::new(self.steps.clone(), self.step_idx);
      return StateResult::Done {
        next: Box::new(next),
        output: None,
      };
    }

    self.tick += 1;
    StateResult::Continue
  }

  fn handle_action(&mut self, action: WizardAction, _ui: &mut UiController) -> StateResult {
    match action {
      WizardAction::Exit => StateResult::Finished,
      _ => StateResult::Continue,
    }
  }
}

fn entrance_progress(map: &DistanceMap, tick: usize) -> f64 {
  let total_estimate = (map.max_distance / mascot_fx::REVEAL_SPEED) as usize + 100;
  (tick as f64 / total_estimate as f64).min(1.0)
}
