package de.miaurizius.jgame2d.core.handlers;

import de.miaurizius.jgame2d.core.Boot;
import de.miaurizius.jgame2d.core.GamePanel;
import de.miaurizius.jgame2d.core.UI;
import de.miaurizius.jgame2d.core.enums.GameState;
import de.miaurizius.jgame2d.core.enums.Map;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.logging.Level;

public class KeyHandler implements KeyListener {

    public boolean upPressed, downPressed, leftPressed, rightPressed, spacePressed, shotKeyPressed, CTLKeyPressed;
    public GamePanel panel;
    public boolean debug;

    public KeyHandler(GamePanel panel) {
        this.panel = panel;
    }

    // STATE SPECIFIC KEYBIND CONFIGURATION
    private void handleTitle(int code) {
        switch (code) {
            case KeyEvent.VK_UP -> {
                if(panel.ui.commandNum != 0) panel.ui.commandNum--;
            }
            case KeyEvent.VK_DOWN -> {
                if(panel.ui.commandNum != 2) panel.ui.commandNum++;
            }
            case KeyEvent.VK_ENTER, KeyEvent.VK_SPACE -> {
                switch (panel.ui.commandNum) {
                    case 0:
                        panel.gameState = GameState.PLAY;
                        panel.playMusic(0);
                        break;
                    case 1:
                        System.out.printf("Loading config...%n");
                        try {
                            panel.config.load();
                            panel.saveLoad.load();
                            panel.gameState = GameState.PLAY;
                            panel.playMusic(0);
                        } catch (Exception e) {
                            Boot.logger.log(Level.SEVERE, "Failed to load config", e);
                        }
                        break;
                    case 2:
                        System.exit(0);
                        break;
                }
            }
        }
    }
    private void handlePlay(int code) {
        switch (code) {
            // CONTROLS
            case KeyEvent.VK_W, KeyEvent.VK_UP -> upPressed = true;
            case KeyEvent.VK_S, KeyEvent.VK_DOWN -> downPressed = true;
            case KeyEvent.VK_A, KeyEvent.VK_LEFT -> leftPressed = true;
            case KeyEvent.VK_D, KeyEvent.VK_RIGHT -> rightPressed = true;
            case KeyEvent.VK_CONTROL -> CTLKeyPressed = true;
            case KeyEvent.VK_SPACE -> spacePressed = true;
            //case KeyEvent.VK_F -> shotKeyPressed = true;

            // MINI MAP TOGGLE
            case KeyEvent.VK_X -> panel.mapMan.miniMapOn = !panel.mapMan.miniMapOn;

            // DEBUG OPTIONS
            case KeyEvent.VK_T -> debug = !debug;
            case KeyEvent.VK_R -> {for(Map m : Map.values()) panel.tileM.loadMap(m);}

            // GAME STATES
            case KeyEvent.VK_ESCAPE -> {
                panel.gameState = GameState.PAUSE;
                panel.ui.optionState = UI.OptionState.OVERVIEW;
                panel.ui.commandNum = 0;
            }
            case KeyEvent.VK_C -> panel.gameState = GameState.CHARACTER;
            case KeyEvent.VK_M -> panel.gameState = GameState.MAP;
        }
    }
    private void handlePause(int code) {
        if(code == KeyEvent.VK_SPACE) spacePressed = true;

        int maxCommandNum = 0;

        switch (panel.ui.optionState) {
            case OVERVIEW -> maxCommandNum = 5;
            case QUITNF -> maxCommandNum = 1;
        }

        switch(code) {
            case KeyEvent.VK_UP:
                if(panel.ui.commandNum <= 0) break;
                panel.ui.commandNum--;
                panel.playSE(9);
                break;
            case KeyEvent.VK_DOWN:
                if(panel.ui.commandNum >= maxCommandNum) break;
                panel.ui.commandNum++;
                panel.playSE(9);
                break;
            case KeyEvent.VK_LEFT:
                if(panel.ui.optionState == UI.OptionState.OVERVIEW)
                    if(panel.ui.commandNum == 1 && panel.music.volumeScale > 0) {
                        panel.music.volumeScale--;
                        panel.music.checkVolume();
                        panel.playSE(9);
                    } else if(panel.ui.commandNum == 2 && panel.sfx.volumeScale > 0) {
                        panel.sfx.volumeScale--;
                        panel.playSE(9);
                    }
                break;
            case KeyEvent.VK_RIGHT:
                if(panel.ui.optionState == UI.OptionState.OVERVIEW) {
                    if(panel.ui.commandNum == 1 && panel.music.volumeScale < 5) {
                        panel.music.volumeScale++;
                        panel.music.checkVolume();
                        panel.playSE(9);
                    } else if(panel.ui.commandNum == 2 && panel.sfx.volumeScale < 5) {
                        panel.sfx.volumeScale++;
                        panel.playSE(9);
                    }
                }
                break;
        }

        // EXIT STATE
        if(code == KeyEvent.VK_ESCAPE)
            if(panel.ui.optionState == UI.OptionState.OVERVIEW) panel.gameState = GameState.PLAY; else panel.ui.optionState = UI.OptionState.OVERVIEW;
    }
    private void handleDialogue(int code) {
        // EXIT STATE
        if (code == KeyEvent.VK_SPACE) {
            spacePressed = true;
        }
    }
    private void handleCharacter(int code) {
        switch (code) {
            case KeyEvent.VK_UP, KeyEvent.VK_DOWN, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT -> playerInventory(code);
            case KeyEvent.VK_SPACE -> panel.player.selectItem();

            // EXIT STATE
            case KeyEvent.VK_C, KeyEvent.VK_ESCAPE -> panel.gameState = GameState.PLAY;
        }
    }
    private void handleGameOver(int code) {
        switch(code) {
            case KeyEvent.VK_UP:
                if (panel.ui.commandNum <= 0) break;
                panel.ui.commandNum--;
                panel.playSE(9);
                break;
            case KeyEvent.VK_DOWN:
                if (panel.ui.commandNum >= 1) break;
                panel.ui.commandNum++;
                panel.playSE(9);
                break;
            case KeyEvent.VK_SPACE:
                if(panel.ui.commandNum == 0) {
                    panel.gameState = GameState.PLAY;
                    panel.playMusic(0);
                    panel.resetGame(false);
                }
                if(panel.ui.commandNum == 1) {
                    panel.gameState = GameState.TITLE;
                    panel.ui.commandNum = 0;
                    panel.resetGame(true);
                    panel.stopMusic();
                }
        }
    }
    private void handleTrade(int code) {
        if(code == KeyEvent.VK_SPACE) spacePressed = true;
        if(panel.ui.tradeState == UI.TradeState.SELECT) {
            switch (code) {
                case KeyEvent.VK_UP:
                    if (panel.ui.commandNum <= 0) break;
                    panel.ui.commandNum--;
                    panel.playSE(9);
                    break;
                case KeyEvent.VK_DOWN:
                    if (panel.ui.commandNum >= 2) break;
                    panel.ui.commandNum++;
                    panel.playSE(9);
                    break;
            }
        }
        if(panel.ui.tradeState == UI.TradeState.BUY) {
            npcInventory(code);
            if(code == KeyEvent.VK_ESCAPE) panel.ui.tradeState = UI.TradeState.SELECT;
        }
        if(panel.ui.tradeState == UI.TradeState.SELL) {
            playerInventory(code);
            if(code == KeyEvent.VK_ESCAPE) panel.ui.tradeState = UI.TradeState.SELECT;
        }
    }
    private void handleMap(int code) {
        switch (code) {
            // EXIT STATE
            case KeyEvent.VK_M, KeyEvent.VK_ESCAPE -> panel.gameState = GameState.PLAY;
        }
    }

    // UTILITY
    private void playerInventory(int code) {
        switch (code) {
            case KeyEvent.VK_UP:
                if(panel.ui.playerSlotRow == 0) break;
                if(panel.sfx.clips[9].isRunning()) break;
                panel.ui.playerSlotRow--;
                panel.playSE(9);
                break;
            case KeyEvent.VK_DOWN:
                if(panel.ui.playerSlotRow == 3) break;
                if(panel.sfx.clips[9].isRunning()) break;
                panel.ui.playerSlotRow++;
                panel.playSE(9);
                break;
            case KeyEvent.VK_LEFT:
                if(panel.ui.playerSlotCol == 0) break;
                if(panel.sfx.clips[9].isRunning()) break;
                panel.ui.playerSlotCol--;
                panel.playSE(9);
                break;
            case KeyEvent.VK_RIGHT:
                if(panel.ui.playerSlotCol == 4) break;
                if(panel.sfx.clips[9].isRunning()) break;
                panel.ui.playerSlotCol++;
                panel.playSE(9);
                break;
        }
    }
    private void npcInventory(int code) {
        switch (code) {
            case KeyEvent.VK_UP:
                if(panel.ui.npcSlotRow == 0) break;
                if(panel.sfx.clips[9].isRunning()) break;
                panel.ui.npcSlotRow--;
                panel.playSE(9);
                break;
            case KeyEvent.VK_DOWN:
                if(panel.ui.npcSlotRow == 3) break;
                if(panel.sfx.clips[9].isRunning()) break;
                panel.ui.npcSlotRow++;
                panel.playSE(9);
                break;
            case KeyEvent.VK_LEFT:
                if(panel.ui.npcSlotCol == 0) break;
                if(panel.sfx.clips[9].isRunning()) break;
                panel.ui.npcSlotCol--;
                panel.playSE(9);
                break;
            case KeyEvent.VK_RIGHT:
                if(panel.ui.npcSlotCol == 4) break;
                if(panel.sfx.clips[9].isRunning()) break;
                panel.ui.npcSlotCol++;
                panel.playSE(9);
                break;
        }
    }

    // KEY-LISTENER
    @Override
    public void keyTyped(KeyEvent e) {}
    @Override
    public void keyPressed(KeyEvent e) {
        int code = e.getKeyCode();
        switch(panel.gameState) {
            case PLAY -> handlePlay(code);
            case DIALOGUE -> handleDialogue(code);
            case TITLE -> handleTitle(code);
            case PAUSE -> handlePause(code);
            case CHARACTER -> handleCharacter(code);
            case GAMEOVER -> handleGameOver(code);
            case TRADE -> handleTrade(code);
            case MAP -> handleMap(code);
        }
    }
    @Override
    public void keyReleased(KeyEvent e) {
        int code = e.getKeyCode();
        switch (code) {
            case KeyEvent.VK_W,  KeyEvent.VK_UP -> upPressed = false;
            case KeyEvent.VK_S,  KeyEvent.VK_DOWN -> downPressed = false;
            case KeyEvent.VK_A, KeyEvent.VK_LEFT -> leftPressed = false;
            case KeyEvent.VK_D, KeyEvent.VK_RIGHT -> rightPressed = false;
            case KeyEvent.VK_CONTROL -> CTLKeyPressed = false;
            case KeyEvent.VK_F -> shotKeyPressed = false;
        }
    }
}
