import sys
import random
import pygame


def main() -> None:
    pygame.init()

    # 基本参数
    grid_size = 10
    cell_size = 100  # 每格像素
    line_width = 2
    height = grid_size * cell_size + 50  # 增加高度用于显示关卡信息
    width = grid_size * cell_size  # 增加高度用于显示关卡信息

    screen = pygame.display.set_mode((width, height))
    pygame.display.set_caption("扫雷游戏 - 四关挑战")

    # 游戏状态
    current_level = 1
    max_level = 4
    game_won = False
    game_over = False

    # 颜色
    bg_color = (240, 240, 240)
    grid_color = (180, 180, 180)
    mine_color = (220, 50, 50)
    cover_color = (200, 200, 200)
    cover_border_color = (160, 160, 160)
    question_color = (255, 165, 0)  # 橙色用于问号
    level_text_color = (50, 50, 50)
    num_colors = {
        0: (120, 120, 120),
        1: (25, 118, 210),
        2: (56, 142, 60),
        3: (211, 47, 47),
        4: (123, 31, 162),
        5: (244, 81, 30),
        6: (0, 151, 167),
        7: (97, 97, 97),
        8: (0, 0, 0),
    }
    # 重开按钮颜色
    btn_bg_color = (230, 230, 230)
    btn_border_color = (130, 130, 130)
    btn_text_color = (60, 60, 60)

    # 初始化游戏数据
    def init_game():
        nonlocal mines, covered, adjacent_counts, question_marks
        # 随机放置 8 个不重复的雷
        all_cells = [(r, c) for r in range(grid_size) for c in range(grid_size)]
        mines = set(random.sample(all_cells, 8))  # (row, col)

        # 遮盖按钮：True 表示被盖住，False 表示已揭开
        covered = [[True for _ in range(grid_size)] for _ in range(grid_size)]
        
        # 计算周围雷数量
        adjacent_counts = [[0 for _ in range(grid_size)] for _ in range(grid_size)]
        for r in range(grid_size):
            for c in range(grid_size):
                if (r, c) not in mines:
                    adjacent_counts[r][c] = count_adjacent_mines(r, c)
        
        # 根据关卡设置问号
        question_marks = set()
        if current_level > 1:
            # 找出所有非雷的数字格子
            non_mine_cells = [(r, c) for r in range(grid_size) for c in range(grid_size) 
                            if (r, c) not in mines]
            # 随机选择 (current_level - 1) 个格子变为问号
            num_questions = min(current_level - 1, len(non_mine_cells))
            question_marks = set(random.sample(non_mine_cells, num_questions))

    # 辅助函数
    def in_bounds(r: int, c: int) -> bool:
        return 0 <= r < grid_size and 0 <= c < grid_size

    def count_adjacent_mines(r: int, c: int) -> int:
        count = 0
        for dr in (-1, 0, 1):
            for dc in (-1, 0, 1):
                if dr == 0 and dc == 0:
                    continue
                nr, nc = r + dr, c + dc
                if in_bounds(nr, nc) and (nr, nc) in mines:
                    count += 1
        return count

    def flood_fill(r: int, c: int):
        """洪水填充算法：自动展开相邻的0和周围数字"""
        if not in_bounds(r, c) or not covered[r][c] or (r, c) in mines:
            return
        
        # 揭开当前格子
        covered[r][c] = False
        
        # 如果当前格子是0，继续展开相邻格子
        if adjacent_counts[r][c] == 0:
            for dr in (-1, 0, 1):
                for dc in (-1, 0, 1):
                    if dr == 0 and dc == 0:
                        continue
                    nr, nc = r + dr, c + dc
                    flood_fill(nr, nc)

    def check_win():
        """检查是否胜利（所有非雷格子都被揭开）"""
        for r in range(grid_size):
            for c in range(grid_size):
                if (r, c) not in mines and covered[r][c]:
                    return False
        return True

    def next_level():
        """进入下一关"""
        nonlocal current_level, game_won, game_over
        if current_level < max_level:
            current_level += 1
            init_game()
            game_won = False
            game_over = False
        else:
            # 通关了
            game_won = True
            game_over = True

    def restart_game():
        """重开游戏：回到第1关并重置状态"""
        nonlocal current_level, game_won, game_over
        current_level = 1
        game_won = False
        game_over = False
        init_game()

    # 初始化游戏
    mines = set()
    covered = []
    adjacent_counts = []
    question_marks = set()
    init_game()

    # 字体
    pygame.font.init()
    number_font = pygame.font.SysFont(None, int(cell_size * 0.5))
    level_font = pygame.font.SysFont(None, 36)
    button_font = pygame.font.SysFont(None, 28)

    # 加载遮挡纹理，并缩放到单元格尺寸
    try:
        _cover_img_raw = pygame.image.load("lei.png").convert_alpha()
        cover_texture = pygame.transform.smoothscale(_cover_img_raw, (cell_size, cell_size))
    except Exception:
        cover_texture = None

    clock = pygame.time.Clock()

    # 重开按钮区域（底部右侧）
    restart_btn_rect = pygame.Rect(width - 130, grid_size * cell_size + 10, 120, 30)

    running = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.KEYDOWN:
                if event.key in (pygame.K_ESCAPE, pygame.K_q):
                    running = False
                elif event.key == pygame.K_r and game_over:
                    # 重新开始游戏
                    restart_game()
            elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                # 优先检测是否点击了重开按钮（无论是否game_over都可点）
                if restart_btn_rect.collidepoint(event.pos):
                    restart_game()
                elif not game_over:
                    mx, my = event.pos
                    col = mx // cell_size
                    row = my // cell_size
                    if 0 <= row < grid_size and 0 <= col < grid_size and covered[row][col]:
                        # 检查是否踩到雷
                        if (row, col) in mines:
                            game_over = True
                        else:
                            # 使用洪水填充算法展开格子
                            flood_fill(row, col)
                            # 检查是否胜利
                            if check_win():
                                next_level()

        # 背景
        screen.fill(bg_color)

        # 画网格
        for i in range(grid_size + 1):
            # 竖线
            x = i * cell_size
            pygame.draw.line(screen, grid_color, (x, 0), (x, height), line_width)
            # 横线
            y = i * cell_size
            pygame.draw.line(screen, grid_color, (0, y), (width, y), line_width)

        # 画已揭开的内容（雷：红色方块；非雷：显示周围雷数量或问号）
        inset = 14  # 方块边距，让它不贴边
        for row in range(grid_size):
            for col in range(grid_size):
                # 如果游戏结束，显示所有格子；否则只显示已揭开的格子
                should_reveal = not covered[row][col] or game_over
                if should_reveal:
                    if (row, col) in mines:
                        left_top_x = col * cell_size + inset
                        left_top_y = row * cell_size + inset
                        size = cell_size - inset * 2
                        pygame.draw.rect(
                            screen,
                            mine_color,
                            pygame.Rect(left_top_x, left_top_y, size, size),
                            0,
                        )
                    else:
                        # 检查是否是问号格子；若已游戏结束，则显示实际数字
                        if (row, col) in question_marks and not game_over:
                            text_surface = number_font.render("?", True, question_color)
                        else:
                            num = adjacent_counts[row][col]
                            text_surface = number_font.render(str(num), True, num_colors.get(num, (0, 0, 0)))
                        text_rect = text_surface.get_rect()
                        cell_rect = pygame.Rect(col * cell_size, row * cell_size, cell_size, cell_size)
                        text_rect.center = cell_rect.center
                        screen.blit(text_surface, text_rect)

        # 绘制遮盖按钮（在最上层）
        for row in range(grid_size):
            for col in range(grid_size):
                # 如果游戏未结束且格子被遮盖，则绘制遮挡纹理
                should_cover = not game_over and covered[row][col]
                if should_cover:
                    rect = pygame.Rect(col * cell_size, row * cell_size, cell_size, cell_size)
                    if cover_texture is not None:
                        screen.blit(cover_texture, rect.topleft)
                    else:
                        pygame.draw.rect(screen, cover_color, rect)
                    pygame.draw.rect(screen, cover_border_color, rect, 2)

        # 显示关卡信息
        level_text = f"{current_level} / {max_level}"
        level_surface = level_font.render(level_text, True, level_text_color)
        screen.blit(level_surface, (10, grid_size * cell_size + 10))

        # 绘制重开按钮
        pygame.draw.rect(screen, btn_bg_color, restart_btn_rect, border_radius=6)
        pygame.draw.rect(screen, btn_border_color, restart_btn_rect, 2, border_radius=6)
        btn_text_surface = button_font.render("start", True, btn_text_color)
        btn_text_rect = btn_text_surface.get_rect(center=restart_btn_rect.center)
        screen.blit(btn_text_surface, btn_text_rect)

        # 显示游戏状态信息
        if game_over:
            if game_won:
                status_text = "win"
                status_color = (0, 150, 0)
            else:
                status_text = "die"
                status_color = (200, 0, 0)
            status_surface = level_font.render(status_text, True, status_color)
            screen.blit(status_surface, (10, grid_size * cell_size + 35))

        pygame.display.flip()
        clock.tick(60)

    pygame.quit()
    # 处理在某些环境下窗口关闭后卡住的问题
    try:
        sys.exit(0)
    except SystemExit:
        return


if __name__ == "__main__":
    main()

