mod models;
use crate::models::taquin::*;
use crossterm::event::{read, Event, KeyCode, KeyEvent};
use crossterm::terminal::enable_raw_mode;
use left_pad::leftpad;
use std::io::{self, Write};

fn main() {
    let _ = enable_raw_mode();
    let mut taquin_game: TaquinGame = TaquinGame::new();
    let mut playing: bool = true;

    taquin_game.init_grid();
    draw_game(&taquin_game);

    while playing {
        let mut message = "";
        let mut user_cheated: bool = false;
        let mut game_won: bool = false;

        match read().unwrap() {
            Event::Key(KeyEvent {
                code: KeyCode::Char('q'),
                ..
            }) => {
                playing = false;
                message = "Bye bye!";
            }
            Event::Key(KeyEvent {
                code: KeyCode::Char('r'),
                ..
            }) => {
                taquin_game.init_grid();
                user_cheated = false;
                message = "New game started";
            }
            Event::Key(KeyEvent {
                code: KeyCode::Char('s'),
                ..
            }) => {
                taquin_game.resolve();
                user_cheated = true;
                message = "Too hard?";
            }
            Event::Key(KeyEvent {
                code: KeyCode::Up, ..
            }) => {
                if !taquin_game.move_to(Directions::Up) {
                    message = "Cannot move any more up";
                }
            }
            Event::Key(KeyEvent {
                code: KeyCode::Down,
                ..
            }) => {
                if !taquin_game.move_to(Directions::Down) {
                    message = "Cannot move any more down";
                }
            }
            Event::Key(KeyEvent {
                code: KeyCode::Left,
                ..
            }) => {
                if !taquin_game.move_to(Directions::Left) {
                    message = "Cannot move any more left";
                }
            }
            Event::Key(KeyEvent {
                code: KeyCode::Right,
                ..
            }) => {
                if !taquin_game.move_to(Directions::Right) {
                    message = "Cannot move any more right";
                }
            }
            _ => {
                message = "error";
            }
        }

        if taquin_game.is_grid_done() {
            if !user_cheated {
                message = "Yahoo! Good job!";
            }

            game_won = true;
        }

        draw_game(&taquin_game);
        print!("{}\r\n", message);
        let _ = io::stdout().flush();

        if game_won {
            print!("Press 'R' to start a new game, 'Q' to quit.");
            let _ = io::stdout().flush();
            let mut good_choice = false;
            while !good_choice {
                match read().unwrap() {
                    Event::Key(KeyEvent {
                        code: KeyCode::Char('q'),
                        ..
                    }) => {
                        playing = false;
                        good_choice = true;
                    }
                    Event::Key(KeyEvent {
                        code: KeyCode::Char('r'),
                        ..
                    }) => {
                        taquin_game.init_grid();
                        good_choice = true;
                    }
                    _ => {}
                }
            }
        }
    }
}

fn draw_game(game: &TaquinGame) {
    print!("{}[2J", 27 as char);
    let grid = game.grid();

    for i in 0..ROWS * 2 + 1 {
        for j in 0..COLUMNS * 2 + 1 {
            if i == 0 {
                if j == 0 {
                    print!("╔");
                } else if j == COLUMNS * 2 {
                    print!("╗");
                } else if !is_even(j) {
                    print!("═══");
                } else {
                    print!("╦");
                }
            } else if i == ROWS * 2 {
                if j == 0 {
                    print!("╚");
                } else if j == COLUMNS * 2 {
                    print!("╝");
                } else if !is_even(j) {
                    print!("═══");
                } else {
                    print!("╩");
                }
            } else if !is_even(i) {
                if !is_even(j) {
                    print!("{}", leftpad(grid[i / 2][j / 2].to_string(), 3));
                } else {
                    print!("║");
                }
            } else {
                if j == 0 {
                    print!("╠");
                } else if j == COLUMNS * 2 {
                    print!("╣");
                } else if !is_even(j) {
                    print!("═══");
                } else {
                    print!("╬");
                }
            }
        }

        if i == 0 {
            print!("Score: {}", game.score());
        } else if i == 1 {
            print!("High score: {}", game.high_score());
        }

        print!("\r\n");
    }

    print!("Arrows to move\r\n");
    print!("Q: Quit\r\n");
    print!("R: Restart\r\n");
    print!("S: Solve\r\n");
    let _ = io::stdout().flush();
}

fn is_even(num: usize) -> bool {
    return num % 2 == 0;
}
