use rand::Rng;

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

use super::select_input::SelectInput;

const ENCODE_SPEED: f64 = 0.04;
const MORPH_SPEED: f64 = 0.12;
const FADE_SPEED: f64 = 0.06;

#[derive(Clone, Copy, PartialEq)]
enum SubPhase {
  Encode,
  Morph,
  Decode,
}

pub struct Transition {
  steps: Vec<WizardStep>,
  from_idx: usize,
  to_idx: usize,
  prev_input: String,
  sub_phase: SubPhase,
  hint_changing: bool,
}

impl Transition {
  pub fn new(steps: Vec<WizardStep>, from_idx: usize, to_idx: usize, prev_input: String) -> Self {
    let hint_changing = steps[from_idx].hint_text() != steps[to_idx].hint_text();
    Self {
      steps,
      from_idx,
      to_idx,
      prev_input,
      sub_phase: SubPhase::Encode,
      hint_changing,
    }
  }
}

impl WizardState for Transition {
  fn tick(&mut self, ui: &mut UiController, _rng: &mut Box<dyn Rng>) -> StateResult {
    match self.sub_phase {
      SubPhase::Encode => tick_encode(self, ui),
      SubPhase::Morph => tick_morph(self, ui),
      SubPhase::Decode => tick_decode(self, ui),
    }
  }

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

fn tick_encode(state: &mut Transition, ui: &mut UiController) -> StateResult {
  let next_step = &state.steps[state.to_idx];
  let next_has_box = matches!(next_step, WizardStep::Prompt { .. });
  let next_has_selector = matches!(next_step, WizardStep::Select { .. });

  ui.question.reveal = (ui.question.reveal - ENCODE_SPEED).max(0.0);

  if state.hint_changing {
    ui.hint.fade = (ui.hint.fade - FADE_SPEED).max(0.0);
  }

  encode_text_entry(ui, next_has_box);
  encode_selector(ui, next_has_selector);

  if is_fully_encoded(ui, next_has_box, next_has_selector, state.hint_changing) {
    state.sub_phase = SubPhase::Morph;
  }

  StateResult::Continue
}

fn encode_text_entry(ui: &mut UiController, next_has_box: bool) {
  ui.text_entry
    .tick_transition_encode(next_has_box, ENCODE_SPEED, MORPH_SPEED);
}

fn encode_selector(ui: &mut UiController, next_has_selector: bool) {
  ui.selector
    .tick_transition_encode(next_has_selector, ENCODE_SPEED, MORPH_SPEED);
}

// ── Morph phase ────────────────────────────────────────────────────────────────

fn tick_morph(state: &mut Transition, ui: &mut UiController) -> StateResult {
  let next_step = &state.steps[state.to_idx];
  ui_controller::swap_to(ui, next_step);
  state.sub_phase = SubPhase::Decode;
  StateResult::Continue
}

// ── Decode phase ───────────────────────────────────────────────────────────────

fn tick_decode(state: &Transition, ui: &mut UiController) -> StateResult {
  ui.question.reveal = (ui.question.reveal + ENCODE_SPEED).min(1.0);

  if state.hint_changing {
    ui.hint.fade = (ui.hint.fade + FADE_SPEED).min(1.0);
  }

  decode_text_entry(ui);
  decode_selector(ui);

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

  StateResult::Continue
}

fn decode_text_entry(ui: &mut UiController) {
  ui.text_entry
    .tick_transition_decode(ENCODE_SPEED, MORPH_SPEED);
}

fn decode_selector(ui: &mut UiController) {
  ui.selector
    .tick_transition_decode(ENCODE_SPEED, MORPH_SPEED);
}

// ── Completion checks ──────────────────────────────────────────────────────────

fn is_fully_encoded(
  ui: &UiController,
  next_has_box: bool,
  next_has_selector: bool,
  hint_changing: bool,
) -> bool {
  if ui.question.reveal > 0.0 {
    return false;
  }
  if hint_changing && ui.hint.fade > 0.0 {
    return false;
  }
  if ui.text_entry.visible {
    if ui.text_entry.label_reveal > 0.0 || ui.text_entry.content_reveal > 0.0 {
      return false;
    }
    if !next_has_box && ui.text_entry.open > 0.0 {
      return false;
    }
  }
  if ui.selector.visible {
    if !ui.selector.is_fully_hidden() {
      return false;
    }
    if !next_has_selector && !ui.selector.is_fully_closed() {
      return false;
    }
  }
  true
}

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