//! InputSource backed by a replay's recorded key events.

use std::collections::HashMap;

use crate::replay::{KeyKind, Replay};

use super::input::{Action, FrameInput, InputKind, InputSource};

fn action_for(key: &str) -> Option<Action> {
    Some(match key {
        "moveLeft" => Action::MoveLeft,
        "moveRight" => Action::MoveRight,
        "softDrop" => Action::SoftDrop,
        "hardDrop" => Action::HardDrop,
        "rotateCW" => Action::RotateCW,
        "rotateCCW" => Action::RotateCCW,
        "rotate180" => Action::Rotate180,
        "hold" => Action::Hold,
        _ => return None,
    })
}

pub struct ReplayInputSource {
    total_frames: i32,
    by_frame: HashMap<i32, Vec<FrameInput>>,
}

impl ReplayInputSource {
    pub fn new(replay: &Replay) -> ReplayInputSource {
        let mut by_frame: HashMap<i32, Vec<FrameInput>> = HashMap::new();
        for event in &replay.key_events {
            let Some(action) = action_for(&event.key) else {
                continue;
            };
            let kind = match event.kind {
                KeyKind::KeyDown => InputKind::Down,
                KeyKind::KeyUp => InputKind::Up,
            };
            by_frame.entry(event.frame).or_default().push(FrameInput {
                subframe: event.subframe,
                kind,
                action,
                hoisted: event.hoisted,
            });
        }
        ReplayInputSource {
            total_frames: replay.total_frames,
            by_frame,
        }
    }
}

impl InputSource for ReplayInputSource {
    fn frame_inputs(&mut self, frame: i32) -> Vec<FrameInput> {
        self.by_frame.get(&frame).cloned().unwrap_or_default()
    }

    fn has_frame(&self, frame: i32) -> bool {
        frame <= self.total_frames
    }
}
