import pygame
import random
import sys

# 初始化pygame
pygame.init()
WIDTH, HEIGHT = 900, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Plants vs Zombies Demo")
clock = pygame.time.Clock()
FPS = 60

# 颜色常量
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (34, 139, 34)
DARK_GREEN = (0, 100, 0)
YELLOW = (255, 215, 0)
RED = (178, 34, 34)
BROWN = (139, 69, 19)
SKY_BLUE = (135, 206, 235)
GRASS_GREEN = (102, 204, 102)

# 草坪网格参数
GRID_WIDTH = 100
GRID_HEIGHT = 100
ROW_NUM = 5
COL_NUM = 9
OFFSET_X = 50
OFFSET_Y = 50

# 【核心修复】使用 pygame.font.Font(None, size)，不走sysfont，彻底避开报错
font = pygame.font.Font(None, 24)
small_font = pygame.font.Font(None, 18)

# 全局游戏数据
sun = 50
plant_list = []
zombie_list = []
bullet_list = []
game_over = False
selected_plant = None

# 植物属性配置
PLANT_CONFIG = {
    "sunflower": {"cost": 50, "hp": 100, "produce_sun": True, "damage": 0, "color": YELLOW},
    "peashooter": {"cost": 100, "hp": 100, "produce_sun": False, "damage": 25, "color": GREEN}
}

class Plant:
    def __init__(self, row, col, plant_type):
        self.row = row
        self.col = col
        self.x = OFFSET_X + col * GRID_WIDTH
        self.y = OFFSET_Y + row * GRID_HEIGHT
        self.type = plant_type
        self.hp = PLANT_CONFIG[plant_type]["hp"]
        self.max_hp = self.hp
        self.cost = PLANT_CONFIG[plant_type]["cost"]
        self.color = PLANT_CONFIG[plant_type]["color"]
        self.produce_sun = PLANT_CONFIG[plant_type]["produce_sun"]
        self.damage = PLANT_CONFIG[plant_type]["damage"]
        self.timer = 0

    def update(self, dt):
        self.timer += dt
        if self.produce_sun and self.timer >= 5000:
            global sun
            sun += 25
            self.timer = 0
        if not self.produce_sun and self.timer >= 2000:
            has_zombie = any(z.row == self.row for z in zombie_list)
            if has_zombie:
                bullet_list.append(Bullet(self.x + GRID_WIDTH, self.y + GRID_HEIGHT // 2))
                self.timer = 0

    def draw(self):
        pygame.draw.rect(screen, self.color, (self.x + 10, self.y + 10, GRID_WIDTH - 20, GRID_HEIGHT - 20), border_radius=10)
        hp_ratio = self.hp / self.max_hp
        pygame.draw.rect(screen, RED, (self.x + 10, self.y, GRID_WIDTH - 20, 6))
        pygame.draw.rect(screen, GREEN, (self.x + 10, self.y, (GRID_WIDTH - 20) * hp_ratio, 6))

class Bullet:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.speed = 6
        self.radius = 8
        self.damage = 25

    def update(self):
        self.x += self.speed

    def draw(self):
        pygame.draw.circle(screen, BROWN, (int(self.x), int(self.y)), self.radius)

class Zombie:
    def __init__(self, row):
        self.row = row
        self.x = OFFSET_X + COL_NUM * GRID_WIDTH
        self.y = OFFSET_Y + row * GRID_HEIGHT
        self.hp = 150
        self.max_hp = self.hp
        self.speed = 0.4
        self.eat_timer = 0
        self.damage = 25

    def update(self, dt):
        block_plant = None
        for p in plant_list:
            if p.row == self.row and p.x < self.x:
                if block_plant is None or p.x > block_plant.x:
                    block_plant = p
        if block_plant:
            self.eat_timer += dt
            if self.eat_timer >= 1000:
                block_plant.hp -= self.damage
                self.eat_timer = 0
        else:
            self.x -= self.speed
        if self.x < OFFSET_X:
            global game_over
            game_over = True

    def draw(self):
        pygame.draw.rect(screen, (180, 60, 60), (self.x + 10, self.y + 10, GRID_WIDTH - 20, GRID_HEIGHT - 20), border_radius=12)
        hp_ratio = self.hp / self.max_hp
        pygame.draw.rect(screen, BLACK, (self.x + 10, self.y, GRID_WIDTH - 20, 6))
        pygame.draw.rect(screen, (70, 220, 70), (self.x + 10, self.y, (GRID_WIDTH - 20) * hp_ratio, 6))

def draw_grass():
    for r in range(ROW_NUM):
        for c in range(COL_NUM):
            rect = (OFFSET_X + c * GRID_WIDTH, OFFSET_Y + r * GRID_HEIGHT, GRID_WIDTH, GRID_HEIGHT)
            if (r + c) % 2 == 0:
                pygame.draw.rect(screen, GRASS_GREEN, rect)
            else:
                pygame.draw.rect(screen, DARK_GREEN, rect)
            pygame.draw.rect(screen, BLACK, rect, 1)

def draw_shop():
    # 向日葵按钮
    pygame.draw.rect(screen, YELLOW, (20, 10, 80, 60))
    txt1 = small_font.render("Sun(50)", True, BLACK)
    screen.blit(txt1, (23, 32))
    # 豌豆按钮
    pygame.draw.rect(screen, GREEN, (120, 10, 80, 60))
    txt2 = small_font.render("Pea(100)", True, BLACK)
    screen.blit(txt2, (123, 32))
    # 阳光数值
    sun_text = font.render(f"Sun: {sun}", True, YELLOW)
    screen.blit(sun_text, (260, 20))
    # 选中边框
    if selected_plant == "sunflower":
        pygame.draw.rect(screen, WHITE, (20, 10, 80, 60), 3)
    elif selected_plant == "peashooter":
        pygame.draw.rect(screen, WHITE, (120, 10, 80, 60), 3)

def main():
    global sun, selected_plant, game_over
    zombie_spawn_timer = 0
    while True:
        dt = clock.tick(FPS)
        screen.fill(SKY_BLUE)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.MOUSEBUTTONDOWN and not game_over:
                mx, my = pygame.mouse.get_pos()
                # 选择植物
                if 20 < mx < 100 and 10 < my < 70:
                    selected_plant = "sunflower"
                elif 120 < mx < 200 and 10 < my < 70:
                    selected_plant = "peashooter"
                # 种植植物
                if OFFSET_X < mx < OFFSET_X + COL_NUM*GRID_WIDTH and OFFSET_Y < my < OFFSET_Y + ROW_NUM*GRID_HEIGHT:
                    col = (mx - OFFSET_X) // GRID_WIDTH
                    row = (my - OFFSET_Y) // GRID_HEIGHT
                    exists = any(p.row == row and p.col == col for p in plant_list)
                    if not exists and selected_plant:
                        cost = PLANT_CONFIG[selected_plant]["cost"]
                        if sun >= cost:
                            sun -= cost
                            plant_list.append(Plant(row, col, selected_plant))
                            selected_plant = None

        if game_over:
            over_surface = font.render("GAME OVER! Brain Eaten", True, RED)
            screen.blit(over_surface, (WIDTH//2 - 210, HEIGHT//2))
            pygame.display.update()
            continue

        # 生成僵尸
        zombie_spawn_timer += dt
        if zombie_spawn_timer >= 8000:
            zombie_spawn_timer = 0
            rand_row = random.randint(0, ROW_NUM - 1)
            zombie_list.append(Zombie(rand_row))

        # 更新植物
        for plant in plant_list[:]:
            plant.update(dt)
            if plant.hp <= 0:
                plant_list.remove(plant)

        # 更新子弹 + 碰撞
        for bullet in bullet_list[:]:
            bullet.update()
            if bullet.x > WIDTH:
                bullet_list.remove(bullet)
                continue
            for zom in zombie_list[:]:
                dist = ((bullet.x - (zom.x + GRID_WIDTH/2))**2 + (bullet.y - (zom.y + GRID_HEIGHT/2))**2)**0.5
                if dist < 40:
                    zom.hp -= bullet.damage
                    bullet_list.remove(bullet)
                    if zom.hp <= 0:
                        zombie_list.remove(zom)
                    break

        # 更新僵尸
        for zom in zombie_list:
            zom.update(dt)

        # 渲染所有画面
        draw_grass()
        draw_shop()
        for p in plant_list: p.draw()
        for z in zombie_list: z.draw()
        for b in bullet_list: b.draw()

        pygame.display.flip()

if __name__ == "__main__":
    main()