import pygame
import sys
import random

# ========== 初始化 ==========
pygame.init()
WIDTH, HEIGHT = 600, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Memory Match – 2 Levels")
clock = pygame.time.Clock()

# ========== 配色 ==========
BG_TOP = (255, 245, 240)
BG_BOTTOM = (240, 230, 250)
CARD_BACK = (255, 255, 255)
CARD_BORDER = (200, 180, 220)
CARD_SHADOW = (180, 160, 200)
TEXT_COLOR = (80, 60, 80)
SCORE_COLOR = (255, 100, 150)
WIN_COLOR = (255, 200, 50)

# ========== 字体 ==========
font_small = pygame.font.Font(None, 28)
font_med = pygame.font.Font(None, 34)
font_large = pygame.font.Font(None, 48)
font_emoji = pygame.font.Font(None, 46)

# ========== 关卡定义 ==========
# 第一关：3x3，4对 + 一颗星
# 第二关：4x4，8对，无特殊卡
LEVELS = [
    {"rows": 3, "cols": 3, "pairs": ["Cat", "Dog", "Fish", "Bird"], "special": True},
    {"rows": 4, "cols": 4, "pairs": ["Cat", "Dog", "Fish", "Bird", "Frog", "Bear", "Lion", "Duck"], "special": False}
]

SPECIAL_SYMBOL = "⭐"

# ========== 卡片类 ==========
class Card:
    def __init__(self, x, y, size, content):
        self.x = x
        self.y = y
        self.size = size
        self.content = content
        self.flipped = False
        self.matched = False
        self.is_special = (content == SPECIAL_SYMBOL)
        self.rect = pygame.Rect(x, y, size, size)

    def draw(self, surface):
        # 阴影
        shadow_rect = pygame.Rect(self.x + 4, self.y + 4, self.size, self.size)
        pygame.draw.rect(surface, CARD_SHADOW, shadow_rect, border_radius=12)
        # 卡片主体
        color = CARD_BACK
        if self.flipped:
            color = (255, 250, 240)
        rect = pygame.Rect(self.x, self.y, self.size, self.size)
        pygame.draw.rect(surface, color, rect, border_radius=12)
        pygame.draw.rect(surface, CARD_BORDER, rect, 3, border_radius=12)
        # 内容
        if self.flipped or self.matched:
            if self.matched:
                content_surf = font_emoji.render(self.content, True, (150, 150, 150))
            else:
                content_surf = font_emoji.render(self.content, True, TEXT_COLOR)
            content_rect = content_surf.get_rect(center=(self.x + self.size//2, self.y + self.size//2))
            surface.blit(content_surf, content_rect)
        else:
            q_surf = font_large.render("?", True, (180, 160, 200))
            q_rect = q_surf.get_rect(center=(self.x + self.size//2, self.y + self.size//2))
            surface.blit(q_surf, q_rect)

# ========== 游戏主类 ==========
class MemoryGame:
    def __init__(self):
        self.level = 0          # 当前关卡索引
        self.load_level()

    def load_level(self):
        """根据当前关卡索引加载配置并初始化"""
        if self.level >= len(LEVELS):
            self.state = "all_clear"
            return
        level_data = LEVELS[self.level]
        self.rows = level_data["rows"]
        self.cols = level_data["cols"]
        self.pairs = level_data["pairs"]
        self.has_special = level_data["special"]

        # 计算卡片尺寸和布局
        # 根据窗口动态调整，保证卡片不会太大也不会太小
        max_card_width = (WIDTH - 80) // self.cols
        max_card_height = (HEIGHT - 120) // self.rows
        self.card_size = min(max_card_width, max_card_height, 100)  # 最大不超过100
        self.gap = 10
        total_width = self.cols * (self.card_size + self.gap) - self.gap
        total_height = self.rows * (self.card_size + self.gap) - self.gap
        self.board_x = (WIDTH - total_width) // 2
        self.board_y = (HEIGHT - total_height) // 2 + 20  # 给标题留空间

        # 生成卡片内容列表
        contents = self.pairs * 2
        if self.has_special:
            contents.append(SPECIAL_SYMBOL)
        random.shuffle(contents)

        self.cards = []
        for row in range(self.rows):
            for col in range(self.cols):
                idx = row * self.cols + col
                x = self.board_x + col * (self.card_size + self.gap)
                y = self.board_y + row * (self.card_size + self.gap)
                self.cards.append(Card(x, y, self.card_size, contents[idx]))

        self.selected = []
        self.matches = 0
        self.total_pairs = len(self.pairs)
        self.state = "playing"
        self.lock = False
        self.flip_timer = 0
        self.moves = 0
        self.special_collected = 0

    def handle_click(self, pos):
        if self.state != "playing" or self.lock:
            return
        for i, card in enumerate(self.cards):
            if card.rect.collidepoint(pos):
                if card.flipped or card.matched:
                    continue
                card.flipped = True
                self.selected.append(i)

                if len(self.selected) == 1:
                    # 如果翻开的是特殊卡（仅第一关有）
                    if card.is_special:
                        self.special_collected += 1
                        card.matched = True
                        self.selected = []
                        self.shuffle_remaining()
                elif len(self.selected) == 2:
                    self.moves += 1
                    idx1, idx2 = self.selected
                    c1, c2 = self.cards[idx1], self.cards[idx2]
                    # 第二张是特殊卡的情况
                    if c2.is_special:
                        self.special_collected += 1
                        c2.matched = True
                        c1.flipped = False
                        self.selected = []
                        self.shuffle_remaining()
                    else:
                        # 普通配对
                        if c1.content == c2.content and not c1.is_special:
                            c1.matched = True
                            c2.matched = True
                            self.matches += 1
                            self.selected = []
                            # 检查是否本关完成
                            if self.matches == self.total_pairs:
                                self.state = "win"
                        else:
                            self.lock = True
                            self.flip_timer = 35
                break

    def shuffle_remaining(self):
        """将剩余未翻开且未匹配的卡片内容随机重排"""
        remaining = [i for i, c in enumerate(self.cards) if not c.flipped and not c.matched]
        contents = [self.cards[i].content for i in remaining]
        random.shuffle(contents)
        for idx, new_content in zip(remaining, contents):
            self.cards[idx].content = new_content

    def update(self):
        if self.lock:
            self.flip_timer -= 1
            if self.flip_timer <= 0:
                for idx in self.selected:
                    self.cards[idx].flipped = False
                self.selected = []
                self.lock = False

    def next_level(self):
        """进入下一关，若没有下一关则标记全部通关"""
        self.level += 1
        if self.level < len(LEVELS):
            self.load_level()
        else:
            self.state = "all_clear"

    def draw_background(self):
        for y in range(HEIGHT):
            ratio = y / HEIGHT
            r = int(BG_TOP[0] + (BG_BOTTOM[0] - BG_TOP[0]) * ratio)
            g = int(BG_TOP[1] + (BG_BOTTOM[1] - BG_TOP[1]) * ratio)
            b = int(BG_TOP[2] + (BG_BOTTOM[2] - BG_TOP[2]) * ratio)
            pygame.draw.line(screen, (r, g, b), (0, y), (WIDTH, y))

    def draw_ui(self):
        # 标题
        if self.state != "all_clear":
            title_surf = font_large.render(f"Level {self.level+1}  Memory", True, TEXT_COLOR)
        else:
            title_surf = font_large.render("All Clear!", True, TEXT_COLOR)
        screen.blit(title_surf, (WIDTH//2 - title_surf.get_width()//2, 15))

        if self.state != "all_clear":
            moves_text = font_small.render(f"Moves: {self.moves}", True, SCORE_COLOR)
            screen.blit(moves_text, (20, HEIGHT - 40))
            if self.has_special:
                star_text = font_small.render(f"⭐ x {self.special_collected}", True, SCORE_COLOR)
                screen.blit(star_text, (WIDTH - 120, HEIGHT - 40))

        # 胜利/通关画面
        if self.state == "win":
            overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
            overlay.fill((0,0,0, 180))
            screen.blit(overlay, (0,0))
            win_text = font_large.render("Level Complete!", True, WIN_COLOR)
            screen.blit(win_text, (WIDTH//2 - win_text.get_width()//2, HEIGHT//2 - 50))
            next_text = font_med.render("Press SPACE to continue", True, (255,255,255))
            screen.blit(next_text, (WIDTH//2 - next_text.get_width()//2, HEIGHT//2 + 20))
        elif self.state == "all_clear":
            overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
            overlay.fill((0,0,0, 180))
            screen.blit(overlay, (0,0))
            win_text = font_large.render("🎉 All Clear!", True, WIN_COLOR)
            screen.blit(win_text, (WIDTH//2 - win_text.get_width()//2, HEIGHT//2 - 50))
            restart_text = font_med.render("Press R to play again", True, (255,255,255))
            screen.blit(restart_text, (WIDTH//2 - restart_text.get_width()//2, HEIGHT//2 + 20))

    def draw(self):
        self.draw_background()
        for card in self.cards:
            card.draw(screen)
        self.draw_ui()

# ========== 主循环 ==========
def main():
    game = MemoryGame()
    running = True
    while running:
        dt = clock.tick(60) / 1000.0

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                if game.state == "playing":
                    game.handle_click(event.pos)
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    if game.state == "win":
                        game.next_level()
                if event.key == pygame.K_r:
                    if game.state == "all_clear":
                        game.level = 0
                        game.load_level()
                    else:
                        game.load_level()  # 重玩当前关

        game.update()
        game.draw()
        pygame.display.flip()

    pygame.quit()
    sys.exit()

if __name__ == "__main__":
    main()