use rand::rngs::ThreadRng;

use crate::wizard::WizardStep;
use crate::wizard::state::{StateResult, WizardAction, WizardState};
use crate::wizard::ui_controller::UiController;

use super::input::Input;
use super::select_input::SelectInput;

const REVEAL_SPEED: f64 = 0.04;
const BOX_OPEN_SPEED: f64 = 0.08;
const FADE_SPEED: f64 = 0.06;

pub struct Decode {
  steps: Vec<WizardStep>,
  step_idx: usize,
}

impl Decode {
  pub fn new(steps: Vec<WizardStep>, step_idx: usize) -> Self {
    Self { steps, step_idx }
  }
}

impl WizardState for Decode {
  fn tick(&mut self, ui: &mut UiController, _rng: &mut ThreadRng) -> StateResult {
    advance_question_reveal(ui);
    advance_input_box(ui);
    advance_selector(ui);
    advance_hint(ui);

    if is_decode_complete(ui) {
      let next: Box<dyn WizardState> = match &self.steps[self.step_idx] {
        WizardStep::Select { .. } => Box::new(SelectInput::new(self.steps.clone(), self.step_idx)),
        _ => Box::new(Input::new(self.steps.clone(), self.step_idx)),
      };
      return StateResult::Done { next, output: None };
    }

    StateResult::Continue
  }

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

fn advance_question_reveal(ui: &mut UiController) {
  ui.question.reveal = (ui.question.reveal + REVEAL_SPEED).min(1.0);
}

fn advance_input_box(ui: &mut UiController) {
  if !ui.input_box.visible || ui.question.reveal < 0.5 {
    return;
  }
  ui.input_box.open = (ui.input_box.open + BOX_OPEN_SPEED).min(1.0);
  if ui.input_box.open >= 1.0 {
    ui.input_box.label_reveal = (ui.input_box.label_reveal + REVEAL_SPEED).min(1.0);
    ui.input_box.content_reveal = (ui.input_box.content_reveal + REVEAL_SPEED).min(1.0);
  }
}

fn advance_selector(ui: &mut UiController) {
  if !ui.selector.visible || ui.question.reveal < 0.5 {
    return;
  }
  ui.selector.open = (ui.selector.open + BOX_OPEN_SPEED).min(1.0);
  if ui.selector.open >= 1.0 {
    ui.selector.reveal = (ui.selector.reveal + REVEAL_SPEED).min(1.0);
  }
}

fn advance_hint(ui: &mut UiController) {
  ui.hint.fade = (ui.hint.fade + FADE_SPEED).min(1.0);
}

fn is_decode_complete(ui: &UiController) -> bool {
  if ui.question.reveal < 1.0 || ui.hint.fade < 1.0 {
    return false;
  }
  if ui.input_box.visible {
    return ui.input_box.open >= 1.0
      && ui.input_box.label_reveal >= 1.0
      && ui.input_box.content_reveal >= 1.0;
  }
  if ui.selector.visible {
    return ui.selector.open >= 1.0 && ui.selector.reveal >= 1.0;
  }
  true
}
