package tetris;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;
import java.util.Random;

public class GamePanel extends JPanel {
    private static final int BLOCK_SIZE = 30;
    private static final int ROWS = 20, COLS = 10;
    private final int[][] board = new int[ROWS][COLS];
    private Block currentBlock, nextBlock;
    private Timer timer;
    private int fallSpeed = 500, score = 0;
    private final NextBlockPanel nextBlockPanel;
    private final ResourceManager resManager = ResourceManager.getInstance();

    public GamePanel(NextBlockPanel nextBlockPanel) {
        this.nextBlockPanel = nextBlockPanel;
        setPreferredSize(new Dimension(COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE));
        setBackground(Color.BLACK);
        initControls();
        initTimer();
        newGame();

        addComponentListener(new ComponentAdapter() {
            @Override
            public void componentShown(ComponentEvent e) {
                requestFocusInWindow();
            }
        });
    }

    private void initControls() {
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                switch (e.getKeyCode()) {
                    case KeyEvent.VK_SPACE:
                        togglePause();
                        break;
                    case KeyEvent.VK_LEFT:
                        if (!isPaused && !isGameOver) handleMove(-1, 0);
                        break;
                    case KeyEvent.VK_RIGHT:
                        if (!isPaused && !isGameOver) handleMove(1, 0);
                        break;
                    case KeyEvent.VK_DOWN:
                        if (!isPaused && !isGameOver) hardDrop();
                        break;
                    case KeyEvent.VK_UP:
                        if (!isPaused && !isGameOver) rotateBlock();
                        break;
                }
                repaint();
            }
        });
    }

    private void handleMove(int dx, int dy) {
        if (canMove(dx, dy)) {
            if (dx == -1) currentBlock.moveLeft();
            else if (dx == 1) currentBlock.moveRight();
        }
    }

    public void togglePause() {
        isPaused = !isPaused;
        if (timer != null) {
            if (isPaused) {
                timer.stop();
            } else {
                timer.setDelay(fallSpeed);
                timer.start();
            }
        }
        Toolkit.getDefaultToolkit().beep();
        requestFocusInWindow();
        repaint();
    }

    private boolean canMove(int dx, int dy) {
        int[][] shape = currentBlock.getShape();
        for (int i = 0; i < shape.length; i++) {
            for (int j = 0; j < shape[i].length; j++) {
                if (shape[i][j] == 1) {
                    int newX = currentBlock.getX() + j + dx;
                    int newY = currentBlock.getY() + i + dy;
                    if (newX < 0 || newX >= COLS || newY >= ROWS || (newY >= 0 && board[newY][newX] != 0))
                        return false;
                }
            }
        }
        return true;
    }

    private void rotateBlock() {
        Block temp = new Block(currentBlock.getType());
        temp.moveTo(currentBlock.getX(), currentBlock.getY());
        temp.rotate();
        if (canRotate(temp)) currentBlock.rotate();
    }

    private boolean canRotate(Block block) {
        int[][] shape = block.getShape();
        for (int i = 0; i < shape.length; i++) {
            for (int j = 0; j < shape[i].length; j++) {
                if (shape[i][j] == 1) {
                    int x = block.getX() + j;
                    int y = block.getY() + i;
                    if (x < 0 || x >= COLS || y >= ROWS || (y >= 0 && board[y][x] != 0))
                        return false;
                }
            }
        }
        return true;
    }

    private void hardDrop() {
        while (canMove(0, 1)) currentBlock.moveDown();
        mergeBlock();
        clearLines();
        spawnNewBlock();
        repaint();
    }

    private void mergeBlock() {
        int[][] shape = currentBlock.getShape();
        for (int i = 0; i < shape.length; i++) {
            for (int j = 0; j < shape[i].length; j++) {
                if (shape[i][j] == 1) {
                    int y = currentBlock.getY() + i;
                    int x = currentBlock.getX() + j;
                    if (y < 0) gameOver();
                    else board[y][x] = currentBlock.getType() + 1;
                }
            }
        }
    }

    private static final int[] SCORE_TABLE = {100, 300, 500, 800};

    private void clearLines() {
        int linesCleared = 0;
        for (int i = ROWS - 1; i >= 0; i--) {
            if (isLineFull(i)) {
                if (i > 0) {
                    System.arraycopy(board, 0, board, 1, i);
                }
                Arrays.fill(board[0], 0);
                linesCleared++;
                i++;
            }
        }
        if (linesCleared > 0) {
            resManager.playClearSound();  // 添加消除音效
            score += (linesCleared < 4) ? SCORE_TABLE[linesCleared - 1] : SCORE_TABLE[3];
            Toolkit.getDefaultToolkit().beep();
            nextBlockPanel.updateScore();
        }
    }

    private boolean isLineFull(int row) {
        for (int cell : board[row])
            if (cell == 0) return false;
        return true;
    }

    private void spawnNewBlock() {
        currentBlock = (nextBlock != null) ? nextBlock : new Block(new Random().nextInt(7));
        nextBlock = new Block(new Random().nextInt(7));
        nextBlockPanel.setNextBlock(nextBlock);
        if (!canSpawn()) gameOver();
    }

    private boolean canSpawn() {
        if (currentBlock.getY() < 0) return false;

        int[][] shape = currentBlock.getShape();
        for (int i = 0; i < shape.length; i++) {
            for (int j = 0; j < shape[i].length; j++) {
                if (shape[i][j] == 1) {
                    int y = currentBlock.getY() + i;
                    int x = currentBlock.getX() + j;
                    if (x < 0 || x >= COLS || y >= ROWS || y < 0 || board[y][x] != 0)
                        return false;
                }
            }
        }
        return true;
    }

    public void newGame() {
        for (int[] row : board) Arrays.fill(row, 0);
        score = 0;
        spawnNewBlock();
        isGameOver = isPaused = false;
        if (timer != null) {
            timer.start();
        }
        requestFocusInWindow();
    }

    private void initTimer() {
        timer = new Timer(fallSpeed, e -> {
            if (!isPaused && !isGameOver) {
                if (canMove(0, 1)) {
                    currentBlock.moveDown();
                } else {
                    mergeBlock();
                    clearLines();
                    spawnNewBlock();
                }
                repaint();
            }
        });
    }

    public void setFallSpeed(int speed) {
        fallSpeed = speed;
        if (timer != null) {
            timer.setDelay(speed);
            if (!isPaused) {
                timer.restart();
            }
        }
    }

    public int getScore() {
        return score;
    }

    private void gameOver() {
        isGameOver = true;
        timer.stop();
        JOptionPane.showMessageDialog(this, "得分: " + score);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        // 绘制游戏背景图
        Image gameBg = resManager.getGameBackground();
        if (gameBg != null) {
            g.drawImage(gameBg, 0, 0, getWidth(), getHeight(), this);
        }

        // 绘制固定方块
        for (int i = 0; i < ROWS; i++) {
            for (int j = 0; j < COLS; j++) {
                if (board[i][j] != 0) {
                    int type = board[i][j] - 1;
                    Image blockImage = resManager.getBlockImage(type);
                    if (blockImage != null) {
                        g.drawImage(blockImage, j * BLOCK_SIZE, i * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, this);
                    }
                }
            }
        }

        // 绘制当前方块
        if (currentBlock != null) {
            int[][] shape = currentBlock.getShape();
            for (int i = 0; i < shape.length; i++) {
                for (int j = 0; j < shape[i].length; j++) {
                    if (shape[i][j] == 1) {
                        int x = (currentBlock.getX() + j) * BLOCK_SIZE;
                        int y = (currentBlock.getY() + i) * BLOCK_SIZE;
                        if (y < getHeight()) {
                            int type = currentBlock.getType();
                            Image blockImage = resManager.getBlockImage(type);
                            if (blockImage != null) {
                                g.drawImage(blockImage, x, y, BLOCK_SIZE, BLOCK_SIZE, this);
                            }
                        }
                    }
                }
            }
        }
    }

    private boolean isPaused = false, isGameOver = false;
}