package eu.midnightdust.yaytris.ui;

import eu.midnightdust.yaytris.HighScores;
import eu.midnightdust.yaytris.Tetris;
import eu.midnightdust.yaytris.util.CatppuccinColor;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.LineBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.IOException;

import static eu.midnightdust.yaytris.Settings.guiScale;
import static eu.midnightdust.yaytris.Translation.t;

public class TetrisUI extends JFrame implements KeyListener {
    JLabel titleLabel;
    GameCanvas gamePanel;
    JPanel menuPanel;

    public TetrisUI() {
        this.setLayout(null);
        this.setTitle("Tetris");
        this.setSize((int) (400 * guiScale), (int) (300 * guiScale));
        this.setResizable(false);
        this.getContentPane().setBackground(CatppuccinColor.MANTLE.getColor());
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setWindowPosition(this, 0);

        titleLabel = new JLabel("Tetris");
        titleLabel.setForeground(Color.WHITE);
        Image titleImage;
        try {
            titleImage = ImageIO.read(this.getClass().getResourceAsStream("/textures/logo.png"));
        } catch (IOException | NullPointerException ex) {
            throw new RuntimeException(ex);
        }
        titleLabel = new JLabel();
        titleLabel.setIcon(new ImageIcon(new ImageIcon(titleImage).getImage().getScaledInstance(scale(110), scale(30), Image.SCALE_DEFAULT)));
        this.add(titleLabel);

        gamePanel = new GameCanvas(this);
        gamePanel.setBackground(Color.BLACK);
        gamePanel.setBorder(new LineBorder(CatppuccinColor.SURFACE0.getColor(), scale(2)));
        this.add(gamePanel);

        rescale();
        this.addKeyListener(this);
        openMainMenu(null);

        this.setVisible(true);
    }

    private void rescale() {
        this.setSize((int) (400 * guiScale), (int) (300 * guiScale));
        titleLabel.setBounds(scale(225), scale(7), scale(110), scale(30));
        gamePanel.setBounds(scale(10), scale(10), scale(150), scale(256));
        for (Component comp : this.getComponents()){
            if (comp instanceof JComponent) setFontScale((JComponent) comp);
        }
    }

    public static int scale(int bound) {
        return (int) (bound * guiScale);
    }
    public static void setFontScale(JComponent label) {
        //if (label.getFont() != null) label.setFont(label.getFont().deriveFont((float) label.getFont().getSize() * guiScale));
    }

    public GameCanvas getGamePanel() {
        return gamePanel;
    }

    public JPanel getMenuPanel() {
        return menuPanel;
    }

    public void startGame(ActionEvent actionEvent) {
        Tetris.startGame();
        this.openScoreMenu(actionEvent);
        this.requestFocus();
        this.repaint();
    }

    public void openMainMenu(ActionEvent actionEvent) {
        if (this.menuPanel != null) this.remove(menuPanel);
        Tetris.resetSpace();
        rescale();
        menuPanel = new MainMenu(scale(170), scale(40), scale(220), scale(226), this);
        menuPanel.setBackground(CatppuccinColor.BASE.getColor());
        menuPanel.setBorder(new LineBorder(CatppuccinColor.SURFACE0.getColor(), scale(2)));
        this.add(menuPanel);
        menuPanel.requestFocus();
        this.transferFocus();
        this.repaint();
    }

    public void openSettings(ActionEvent actionEvent) {
        if (this.menuPanel != null) this.remove(menuPanel);
        menuPanel = new SettingsMenu(scale(170), scale(40), scale(220), scale(226), this);
        menuPanel.setBackground(CatppuccinColor.BASE.getColor());
        menuPanel.setBorder(new LineBorder(CatppuccinColor.SURFACE0.getColor(), scale(2)));
        this.add(menuPanel);
        this.repaint();
    }

    public void openScoreMenu(ActionEvent actionEvent) {
        if (this.menuPanel != null) this.remove(menuPanel);
        menuPanel = new ScoreMenu(scale(170), scale(40), scale(220), scale(226), this);
        menuPanel.setBackground(CatppuccinColor.BASE.getColor());
        menuPanel.setBorder(new LineBorder(CatppuccinColor.SURFACE0.getColor(), scale(2)));
        this.add(menuPanel);
        this.repaint();
    }

    public void openHighscores(ActionEvent actionEvent) {
        if (this.menuPanel != null) this.remove(menuPanel);
        menuPanel = new HighScoreMenu(scale(170), scale(40), scale(220), scale(226), this);
        menuPanel.setBackground(CatppuccinColor.BASE.getColor());
        menuPanel.setBorder(new LineBorder(CatppuccinColor.SURFACE0.getColor(), scale(2)));
        this.add(menuPanel);
        this.repaint();
    }

    public void showHighscoreDialog(int score) {
        String playerName = JOptionPane.showInputDialog(null, t("dialog.highscore.action"), t("dialog.highscore.title"), JOptionPane.PLAIN_MESSAGE);
        HighScores.addScore(playerName, score);
    }

    // Source: https://stackoverflow.com/a/19746437
    private void setWindowPosition(JFrame window, int screen) {
        GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice[] allDevices = env.getScreenDevices();
        int topLeftX, topLeftY, screenX, screenY, windowPosX, windowPosY;

        if (screen < allDevices.length && screen > -1) {
            topLeftX = allDevices[screen].getDefaultConfiguration().getBounds().x;
            topLeftY = allDevices[screen].getDefaultConfiguration().getBounds().y;

            screenX  = allDevices[screen].getDefaultConfiguration().getBounds().width;
            screenY  = allDevices[screen].getDefaultConfiguration().getBounds().height;
        }
        else {
            topLeftX = allDevices[0].getDefaultConfiguration().getBounds().x;
            topLeftY = allDevices[0].getDefaultConfiguration().getBounds().y;

            screenX  = allDevices[0].getDefaultConfiguration().getBounds().width;
            screenY  = allDevices[0].getDefaultConfiguration().getBounds().height;
        }

        windowPosX = ((screenX - window.getWidth())  / 2) + topLeftX;
        windowPosY = ((screenY - window.getHeight()) / 2) + topLeftY;

        window.setLocation(windowPosX, windowPosY);
    }

    @Override
    public void keyPressed(KeyEvent e) {
        switch (e.getKeyCode()) {
            case KeyEvent.VK_E:
                Tetris.getSpace().spawnTetromino();
                break;
            case KeyEvent.VK_UP:
            case KeyEvent.VK_W:
                Tetris.getSpace().getCurrentTetromino().rotate();
                break;
            case KeyEvent.VK_RIGHT:
            case KeyEvent.VK_D:
                Tetris.getSpace().getCurrentTetromino().move(1);
                break;
            case KeyEvent.VK_LEFT:
            case KeyEvent.VK_A:
                Tetris.getSpace().getCurrentTetromino().move(-1);
                break;
            case KeyEvent.VK_DOWN:
            case KeyEvent.VK_S:
                Tetris.getSpace().getCurrentTetromino().fall();
                break;
            case KeyEvent.VK_SPACE:
                Tetris.getSpace().getCurrentTetromino().fallToBottom();
                break;
        }
        gamePanel.repaint();
    }

    // Unused (But required overrides)
    @Override public void keyReleased(KeyEvent e) {}
    @Override public void keyTyped(KeyEvent e) {}
}
