import pygame
import sys
import math
import random

# ===== 初始化 =====
pygame.init()
WIDTH, HEIGHT = 1000, 700
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Radish Defense - 10 Levels")

# ===== 颜色 =====
BG          = (35, 55, 35)
PATH_COLOR  = (175, 155, 95)
GRASS       = (65, 135, 65)
TOWER_COLORS = {
    "basic":   (170, 170, 190),
    "sniper":  (90, 190, 90),
    "machine": (190, 95, 95),
    "cannon":  (195, 145, 45),
    "freeze":  (90, 170, 250),
}
BULLET      = (255, 200, 0)
ENEMY       = (215, 75, 75)
HP_GREEN    = (75, 215, 75)
HP_RED      = (215, 75, 75)
UI_BG       = (40, 40, 60)
UI_TEXT     = (215, 215, 250)
BTN_COLOR   = (65, 95, 145)
BTN_HOVER   = (85, 125, 185)
RADISH_BODY = (235, 115, 155)
RADISH_LVS  = (95, 215, 95)
SLOW_CLR    = (95, 195, 250)
EXPLODE     = (255, 145, 0)
WHITE       = (255, 255, 255)
BLACK       = (0, 0, 0)
YELLOW      = (255, 210, 30)
GOLD        = (255, 215, 0)
PURPLE      = (180, 80, 220)
ORANGE      = (255, 140, 40)
DARK_RED    = (160, 40, 40)
CYAN        = (0, 200, 255)

FPS = 60
clock = pygame.time.Clock()
font = pygame.font.Font(None, 24)
big_font = pygame.font.Font(None, 48)
title_font = pygame.font.Font(None, 72)

# ===== 10个不重复关卡 =====
LEVELS = [
    {"name": "新手村",   "path": [(50, 350), (250, 350), (250, 200), (500, 200), (500, 500), (750, 500), (750, 300), (920, 300)]},
    {"name": "蜿蜒小径", "path": [(50, 200), (300, 200), (300, 450), (550, 450), (550, 250), (800, 250), (800, 500), (920, 500)]},
    {"name": "锯齿峡谷", "path": [(50, 100), (350, 100), (350, 350), (650, 350), (650, 150), (920, 150)]},
    {"name": "马蹄弯道", "path": [(50, 400), (200, 400), (200, 150), (700, 150), (700, 500), (920, 500)]},
    {"name": "螺旋迷宫", "path": [(50, 350), (350, 350), (350, 150), (650, 150), (650, 550), (450, 550), (450, 250), (920, 250)]},
    {"name": "回环之路", "path": [(50, 300), (300, 300), (300, 100), (700, 100), (700, 500), (300, 500), (300, 350), (920, 350)]},
    {"name": "闪电突袭", "path": [(50, 250), (250, 250), (450, 100), (450, 400), (650, 250), (850, 500), (920, 500)]},
    {"name": "蛇行险道", "path": [(50, 180), (200, 180), (200, 350), (400, 350), (400, 180), (600, 180), (600, 500), (850, 500), (850, 300), (920, 300)]},
    {"name": "群山峻岭", "path": [(50, 300), (200, 100), (400, 500), (600, 100), (800, 500), (920, 300)]},
    {"name": "终极决战", "path": [(50, 350), (200, 350), (200, 200), (400, 200), (400, 500), (600, 500), (600, 150), (800, 150), (800, 400), (920, 400)]},
]

# ===== 全局状态 =====
current_level = 0
path = LEVELS[current_level]["path"]
money = 150
health = 10
game_over = False
game_won = False
wave = 1
enemies_defeated = 0
enemies_per_wave = 15
spawn_timer = 0
spawn_delay = 40
selected_tower_type = None
tower_info_visible = False
info_tower = None
level_complete = False
total_score = 0
unlocked_levels = 1

# scene: "start"=标题, "select"=选关, "play"=游戏中
scene = "start"

# ===== 网格系统 =====
CELL = 50
cols, rows = WIDTH // CELL, (HEIGHT - 150) // CELL

def point_to_cell(px, py):
    return px // CELL, py // CELL

def cell_center(cx, cy):
    return cx * CELL + CELL // 2, cy * CELL + CELL // 2

def is_on_path(px, py, margin=28):
    for i in range(len(path) - 1):
        x1, y1 = path[i]
        x2, y2 = path[i+1]
        seg_len = math.sqrt((x2-x1)**2 + (y2-y1)**2)
        if seg_len == 0:
            continue
        t = max(0, min(1, ((px-x1)*(x2-x1) + (py-y1)*(y2-y1)) / (seg_len**2)))
        proj_x = x1 + t * (x2 - x1)
        proj_y = y1 + t * (y2 - y1)
        d = math.sqrt((px - proj_x)**2 + (py - proj_y)**2)
        if d < margin:
            return True
    return False

def is_near_radish(px, py, margin=45):
    rx, ry = path[-1]
    return math.sqrt((px - rx)**2 + (py - ry)**2) < margin

def is_near_tower(px, py, towers, margin=45):
    for t in towers:
        if math.sqrt((px - t.x)**2 + (py - t.y)**2) < margin:
            return True
    return False

def build_grid(towers):
    grid = {}
    for cy in range(rows):
        for cx in range(cols):
            px, py = cell_center(cx, cy)
            if py >= HEIGHT - 150:
                grid[(cx, cy)] = "no"
                continue
            if is_on_path(px, py):
                grid[(cx, cy)] = "no"
            elif is_near_radish(px, py):
                grid[(cx, cy)] = "no"
            elif is_near_tower(px, py, towers):
                grid[(cx, cy)] = "no"
            else:
                grid[(cx, cy)] = "ok"
    return grid

def draw_placement_grid(surface, grid, mouse_pos):
    mx, my = mouse_pos
    mouse_cell = (mx // CELL, my // CELL)
    for (cx, cy), status in grid.items():
        x = cx * CELL
        y = cy * CELL
        if status == "ok":
            s = pygame.Surface((CELL-2, CELL-2), pygame.SRCALPHA)
            s.fill((60, 140, 60, 70))
            surface.blit(s, (x+1, y+1))
            pygame.draw.rect(surface, (80, 180, 80, 120), (x+1, y+1, CELL-2, CELL-2), 1)
            pygame.draw.circle(surface, (80, 220, 80), (x+CELL//2, y+CELL//2), 3)
        else:
            s = pygame.Surface((CELL-2, CELL-2), pygame.SRCALPHA)
            s.fill((180, 60, 60, 40))
            surface.blit(s, (x+1, y+1))
            pygame.draw.rect(surface, (200, 80, 80, 80), (x+1, y+1, CELL-2, CELL-2), 1)
        if mouse_cell == (cx, cy):
            if status == "ok":
                pygame.draw.rect(surface, YELLOW, (x, y, CELL, CELL), 3)
            else:
                pygame.draw.rect(surface, (255, 60, 60), (x, y, CELL, CELL), 3)

# ===== 炮塔类型 =====
TOWER_TYPES = {
    "basic":   {"name": "Basic",   "cost": 60,  "range": 150, "damage": 1,   "cooldown": 30, "color": TOWER_COLORS["basic"]},
    "sniper":  {"name": "Sniper",  "cost": 120, "range": 300, "damage": 3,   "cooldown": 60, "color": TOWER_COLORS["sniper"]},
    "machine": {"name": "Machine", "cost": 100, "range": 120, "damage": 0.5, "cooldown": 10, "color": TOWER_COLORS["machine"]},
    "cannon":  {"name": "Cannon",  "cost": 150, "range": 130, "damage": 2,   "cooldown": 40, "color": TOWER_COLORS["cannon"]},
    "freeze":  {"name": "Freeze",  "cost": 130, "range": 140, "damage": 0.2, "cooldown": 50, "color": TOWER_COLORS["freeze"]},
}

# ===== Tower =====
class Tower:
    def __init__(self, x, y, tower_type):
        self.x = x
        self.y = y
        self.type = tower_type
        self.stats = TOWER_TYPES[tower_type]
        self.range = self.stats["range"]
        self.damage = self.stats["damage"]
        self.cooldown = 0
        self.cooldown_max = self.stats["cooldown"]
        self.cost = self.stats["cost"]
        self.level = 1
        self.color = self.stats["color"]
        self.gun_clr = (max(0, self.color[0]-50), max(0, self.color[1]-50), max(0, self.color[2]-50))
        self.total_invested = self.cost

    def upgrade_cost(self):
        return int(self.cost * 0.8 * self.level)

    def upgrade(self):
        self.level += 1
        self.damage *= 1.5
        self.range *= 1.1
        self.cooldown_max = max(5, int(self.cooldown_max * 0.9))

    def draw(self, s):
        pygame.draw.circle(s, self.color, (self.x, self.y), 20)
        darker = (max(0, self.color[0]-30), max(0, self.color[1]-30), max(0, self.color[2]-30))
        pygame.draw.circle(s, darker, (self.x, self.y), 15)
        for i in range(self.level):
            sx = self.x - 8 + i * 8
            sy = self.y - 22
            pygame.draw.circle(s, YELLOW, (sx, sy), 3)
        if self.type == "basic":
            pygame.draw.rect(s, self.gun_clr, (self.x+5, self.y-5, 25, 10))
        elif self.type == "sniper":
            pygame.draw.rect(s, self.gun_clr, (self.x+5, self.y-3, 35, 6))
            pygame.draw.circle(s, (50, 50, 50), (self.x+40, self.y), 5)
        elif self.type == "machine":
            pygame.draw.rect(s, self.gun_clr, (self.x+5, self.y-8, 25, 6))
            pygame.draw.rect(s, self.gun_clr, (self.x+5, self.y+2, 25, 6))
        elif self.type == "cannon":
            pygame.draw.rect(s, self.gun_clr, (self.x+5, self.y-7, 30, 14))
        elif self.type == "freeze":
            pygame.draw.rect(s, self.gun_clr, (self.x+5, self.y-5, 25, 10))
            pygame.draw.circle(s, (195, 225, 255), (self.x+15, self.y), 8, 2)

    def update(self, enemies):
        if self.cooldown > 0:
            self.cooldown -= 1
            return None
        for e in enemies:
            if not e.active or e.health <= 0:
                continue
            if hasattr(e, 'stealth') and e.stealth and e.stealth_timer % 120 < 60:
                continue
            d = math.sqrt((self.x - e.x)**2 + (self.y - e.y)**2)
            if d <= self.range:
                self.cooldown = self.cooldown_max
                return Bullet(self.x, self.y, e, self.damage, self.type)
        return None

# ===== Bullet =====
class Bullet:
    def __init__(self, x, y, target, damage, btype):
        self.x = x
        self.y = y
        self.target = target
        self.speed = 8
        self.damage = damage
        self.active = True
        self.type = btype
        self.effect = None
        self.size = 5
        if btype == "freeze":
            self.color = (100, 200, 255)
            self.effect = "slow"
            self.effect_duration = 180
        elif btype == "cannon":
            self.color = (255, 150, 0)
            self.size = 8
        elif btype == "machine":
            self.color = BULLET
            self.size = 3
        elif btype == "sniper":
            self.color = (150, 255, 150)
            self.size = 3
        else:
            self.color = BULLET

    def update(self):
        if not self.active or not self.target.active:
            self.active = False
            return False
        dx = self.target.x - self.x
        dy = self.target.y - self.y
        dist = math.sqrt(dx**2 + dy**2)
        if dist < self.speed:
            self.target.health -= self.damage
            if self.effect == "slow":
                self.target.slow_duration = self.effect_duration
                self.target.speed = self.target.original_speed * 0.5
            self.active = False
            return True
        self.x += dx / dist * self.speed
        self.y += dy / dist * self.speed
        return False

    def draw(self, s):
        if self.type == "cannon":
            pygame.draw.circle(s, self.color, (int(self.x), int(self.y)), self.size)
            pygame.draw.circle(s, (255, 200, 100), (int(self.x), int(self.y)), max(1, self.size-3))
        else:
            pygame.draw.circle(s, self.color, (int(self.x), int(self.y)), self.size)
            pygame.draw.circle(s, (255, 255, 200), (int(self.x), int(self.y)), max(1, self.size-2))

# ===== Enemy =====
class Enemy:
    def __init__(self, path, wave, special=None):
        self.path = path
        self.path_index = 0
        self.x, self.y = path[0]
        self.wave = wave
        self.slow_duration = 0
        self.active = True
        base_hp = 5 + (wave - 1) * 2
        base_speed = 1.0 + (wave - 1) * 0.08
        base_reward = 10 + (wave - 1) * 2

        if special == "stealth" and wave >= 4:
            self.type = "stealth"
            self.max_health = int(base_hp * 0.8)
            self.speed = base_speed * 1.3
            self.reward = int(base_reward * 1.5)
            self.color = PURPLE
            self.stealth = True
            self.stealth_timer = 0
        elif special == "bomber" and wave >= 5:
            self.type = "bomber"
            self.max_health = int(base_hp * 1.5)
            self.speed = base_speed * 0.9
            self.reward = int(base_reward * 2)
            self.color = ORANGE
            self.bomb_range = 80
        elif special == "flyer" and wave >= 6:
            self.type = "flyer"
            self.max_health = int(base_hp * 0.6)
            self.speed = base_speed * 2.0
            self.reward = int(base_reward * 1.8)
            self.color = CYAN
            self.fly_target = path[-1]
        elif special == "boss" and wave >= 7:
            self.type = "boss"
            self.max_health = int(base_hp * 5)
            self.speed = base_speed * 0.6
            self.reward = int(base_reward * 5)
            self.color = DARK_RED
        else:
            r = random.random()
            if r < 0.25:
                self.type = "fast"
                self.max_health = int(base_hp * 0.7)
                self.speed = base_speed * 1.8
                self.reward = int(base_reward * 1.3)
                self.color = (220, 120, 120)
            elif r < 0.45:
                self.type = "tank"
                self.max_health = int(base_hp * 3.5)
                self.speed = base_speed * 0.7
                self.reward = int(base_reward * 1.8)
                self.color = (180, 80, 80)
            else:
                self.type = "normal"
                self.max_health = base_hp
                self.speed = base_speed
                self.reward = base_reward
                self.color = ENEMY

        self.health = self.max_health
        self.original_speed = self.speed

    def update(self):
        if not self.active:
            return False
        if self.slow_duration > 0:
            self.slow_duration -= 1
            if self.slow_duration == 0:
                self.speed = self.original_speed
        if hasattr(self, 'stealth') and self.stealth:
            self.stealth_timer += 1
        if self.type == "flyer":
            tx, ty = self.fly_target
            dx = tx - self.x
            dy = ty - self.y
            dist = math.sqrt(dx**2 + dy**2)
            if dist < self.speed:
                self.active = False
                return True
            self.x += dx / dist * self.speed
            self.y += dy / dist * self.speed
            return False
        tx, ty = self.path[self.path_index]
        dx = tx - self.x
        dy = ty - self.y
        dist = math.sqrt(dx**2 + dy**2)
        if dist < self.speed:
            self.path_index += 1
            if self.path_index >= len(self.path):
                self.active = False
                return True
            tx, ty = self.path[self.path_index]
            dx = tx - self.x
            dy = ty - self.y
            dist = math.sqrt(dx**2 + dy**2)
        self.x += dx / dist * self.speed
        self.y += dy / dist * self.speed
        return False

    def draw(self, s):
        if hasattr(self, 'stealth') and self.stealth:
            visible = (self.stealth_timer % 120) < 60
            if not visible:
                alpha_surf = pygame.Surface((30, 30), pygame.SRCALPHA)
                pygame.draw.circle(alpha_surf, (*self.color, 50), (15, 15), 15)
                s.blit(alpha_surf, (int(self.x)-15, int(self.y)-15))
                return
        pygame.draw.circle(s, self.color, (int(self.x), int(self.y)), 15)
        darker = (max(0, self.color[0]-40), max(0, self.color[1]-40), max(0, self.color[2]-40))
        if self.type == "fast":
            pygame.draw.circle(s, darker, (int(self.x), int(self.y)), 10)
            pygame.draw.line(s, (255, 255, 200), (self.x, self.y-15), (self.x, self.y-25), 2)
        elif self.type == "tank":
            d2 = (max(0, self.color[0]-50), max(0, self.color[1]-50), max(0, self.color[2]-50))
            pygame.draw.rect(s, d2, (self.x-12, self.y-5, 24, 10))
            pygame.draw.rect(s, d2, (self.x-5, self.y-12, 10, 24))
        elif self.type == "stealth":
            pygame.draw.circle(s, (200, 100, 240), (int(self.x), int(self.y)), 10, 2)
        elif self.type == "bomber":
            pygame.draw.circle(s, (255, 200, 50), (int(self.x), int(self.y)), 8)
            pygame.draw.circle(s, ORANGE, (int(self.x), int(self.y)), 12, 2)
        elif self.type == "flyer":
            pygame.draw.circle(s, (100, 220, 255), (int(self.x)-5, int(self.y)-8), 5)
            pygame.draw.circle(s, (100, 220, 255), (int(self.x)+5, int(self.y)-8), 5)
        elif self.type == "boss":
            pygame.draw.circle(s, (200, 50, 50), (int(self.x), int(self.y)), 18, 3)
            pygame.draw.polygon(s, GOLD, [(self.x-8, self.y-20), (self.x-5, self.y-28), (self.x, self.y-24), (self.x+5, self.y-28), (self.x+8, self.y-20)])
        else:
            pygame.draw.circle(s, darker, (int(self.x), int(self.y)), 10)
        bw = 40
        pygame.draw.rect(s, HP_RED, (self.x - bw//2, self.y - 30, bw, 5))
        pygame.draw.rect(s, HP_GREEN, (self.x - bw//2, self.y - 30, int(bw * self.health / self.max_health), 5))
        if self.slow_duration > 0:
            pygame.draw.circle(s, SLOW_CLR, (int(self.x), int(self.y)), 18, 2)

# ===== Explosion =====
class Explosion:
    def __init__(self, x, y, radius=30, color=None):
        self.x = x
        self.y = y
        self.radius = 5
        self.max_radius = radius
        self.growth = 2.0 if radius > 30 else 1.5
        self.active = True
        self.color = color if color else EXPLODE

    def update(self):
        self.radius += self.growth
        if self.radius > self.max_radius:
            self.active = False

    def draw(self, s):
        a = int(255 * (1 - self.radius / self.max_radius))
        surf = pygame.Surface((self.max_radius*2, self.max_radius*2), pygame.SRCALPHA)
        pygame.draw.circle(surf, (*self.color, a), (self.max_radius, self.max_radius), int(self.radius), 3)
        pygame.draw.circle(surf, (255, 255, 200, a//2), (self.max_radius, self.max_radius), int(self.radius/2), 2)
        s.blit(surf, (int(self.x - self.max_radius), int(self.y - self.max_radius)))

# ===== 游戏对象 =====
towers = []
bullets = []
enemies = []
explosions = []

# ===== 绘图函数 =====
def draw_path_line():
    for i in range(len(path) - 1):
        pygame.draw.line(screen, PATH_COLOR, path[i], path[i+1], 40)
    pygame.draw.circle(screen, (115, 85, 55), path[0], 20)
    pygame.draw.circle(screen, (140, 110, 75), path[0], 14)

def draw_grass_bg():
    random.seed(42)
    for i in range(0, WIDTH, 40):
        for j in range(0, HEIGHT - 150, 40):
            if random.random() > 0.35:
                pygame.draw.line(screen, GRASS, (i, j), (i, j-14), 2)
    random.seed()

def draw_radish():
    x, y = path[-1]
    pygame.draw.ellipse(screen, RADISH_LVS, (x-24, y-68, 48, 38))
    ld = (max(0, RADISH_LVS[0]-20), max(0, RADISH_LVS[1]-20), max(0, RADISH_LVS[2]-20))
    pygame.draw.ellipse(screen, ld, (x-30, y-58, 28, 28))
    pygame.draw.ellipse(screen, ld, (x+2, y-58, 28, 28))
    pygame.draw.circle(screen, RADISH_BODY, (x, y), 30)
    rd = (max(0, RADISH_BODY[0]-40), max(0, RADISH_BODY[1]-40), max(0, RADISH_BODY[2]-40))
    pygame.draw.ellipse(screen, rd, (x-19, y-14, 38, 28))
    pygame.draw.circle(screen, WHITE, (x-10, y-5), 8)
    pygame.draw.circle(screen, WHITE, (x+10, y-5), 8)
    pygame.draw.circle(screen, BLACK, (x-10, y-5), 4)
    pygame.draw.circle(screen, BLACK, (x+10, y-5), 4)
    pygame.draw.arc(screen, (195, 75, 115), (x-10, y+2, 20, 14), 0, math.pi, 3)
    pygame.draw.rect(screen, HP_RED, (x-30, y-95, 60, 8))
    pygame.draw.rect(screen, HP_GREEN, (x-30, y-95, int(60 * health / 10), 8))

def draw_ui():
    ui_y = HEIGHT - 150
    pygame.draw.rect(screen, UI_BG, (0, 0, WIDTH, 48))
    pygame.draw.rect(screen, (50, 50, 70), (0, ui_y, WIDTH, 150))
    pygame.draw.line(screen, (80, 80, 100), (0, ui_y), (WIDTH, ui_y), 3)

    items = [
        f"Gold: {money}",
        f"HP: {health}",
        f"Level: {current_level+1}/10",
        f"Wave: {wave}",
        f"Killed: {enemies_defeated}",
    ]
    xs = [20, 150, 290, 430, 580]
    for txt, xp in zip(items, xs):
        t = font.render(txt, True, UI_TEXT)
        screen.blit(t, (xp, 14))

    special_hint = ""
    if wave >= 4: special_hint += " [Stealth]"
    if wave >= 5: special_hint += " [Bomber]"
    if wave >= 6: special_hint += " [Flyer]"
    if wave >= 7: special_hint += " [Boss]"
    if special_hint and current_level < 9:
        t = font.render("Special:" + special_hint, True, YELLOW)
        screen.blit(t, (700, 14))

    label = font.render("Towers:", True, UI_TEXT)
    screen.blit(label, (20, ui_y + 15))

    bw, bh, sp = 145, 100, 18
    sx = 20
    mp = pygame.mouse.get_pos()
    for i, (tid, td) in enumerate(TOWER_TYPES.items()):
        x = sx + i * (bw + sp)
        y = ui_y + 42
        r = pygame.Rect(x, y, bw, bh)
        if selected_tower_type == tid:
            c = (max(0, td["color"][0]//2), max(0, td["color"][1]//2), max(0, td["color"][2]//2))
        elif r.collidepoint(mp):
            c = (max(0, int(td["color"][0]/1.2)), max(0, int(td["color"][1]/1.2)), max(0, int(td["color"][2]/1.2)))
        else:
            c = td["color"]
        pygame.draw.rect(screen, c, r)
        bc = (max(0, c[0]//2), max(0, c[1]//2), max(0, c[2]//2))
        pygame.draw.rect(screen, bc, r, 3)
        nt = font.render(td["name"], True, WHITE)
        screen.blit(nt, (x + bw//2 - nt.get_width()//2, y + 8))
        ct = font.render(f"${td['cost']}", True, (255, 255, 180))
        screen.blit(ct, (x + bw//2 - ct.get_width()//2, y + 38))
        ic = (max(0, c[0]-50), max(0, c[1]-50), max(0, c[2]-50))
        pygame.draw.circle(screen, ic, (x + bw//2, y + 75), 14)
        if tid == "sniper":
            pygame.draw.rect(screen, (50, 50, 50), (x + bw//2 + 4, y + 75 - 3, 18, 5))
        elif tid == "machine":
            pygame.draw.rect(screen, (50, 50, 50), (x + bw//2 + 4, y + 75 - 7, 18, 5))
            pygame.draw.rect(screen, (50, 50, 50), (x + bw//2 + 4, y + 75 + 2, 18, 5))
        elif tid == "cannon":
            pygame.draw.rect(screen, (50, 50, 50), (x + bw//2 + 4, y + 75 - 6, 22, 12))
        elif tid == "freeze":
            pygame.draw.circle(screen, (195, 225, 255), (x + bw//2, y + 75), 9, 2)

def draw_tower_info_panel():
    if not tower_info_visible or not info_tower:
        return
    pw, ph = 340, 280
    px, py = WIDTH//2 - pw//2, HEIGHT//2 - ph//2
    surf = pygame.Surface((pw, ph), pygame.SRCALPHA)
    surf.fill((30, 30, 55, 235))
    pygame.draw.rect(surf, (100, 100, 150), (0, 0, pw, ph), 3)
    t = font.render(f"{TOWER_TYPES[info_tower.type]['name']} Lv.{info_tower.level}", True, (255, 255, 200))
    surf.blit(t, (pw//2 - t.get_width()//2, 15))
    stats = [
        f"Damage: {info_tower.damage:.1f}",
        f"Range:  {info_tower.range:.0f}",
        f"Speed:  {60/(info_tower.cooldown_max/60):.1f}/s",
        f"Invested: ${info_tower.total_invested}",
    ]
    for i, s in enumerate(stats):
        lt = font.render(s, True, UI_TEXT)
        surf.blit(lt, (25, 50 + i * 28))
    up_cost = info_tower.upgrade_cost()
    if money >= up_cost and info_tower.level < 5:
        pygame.draw.rect(surf, (60, 140, 60), (40, 180, 120, 35))
        ut = font.render(f"Upgrade ${up_cost}", True, WHITE)
        surf.blit(ut, (100 - ut.get_width()//2, 190))
    elif info_tower.level >= 5:
        ut = font.render("MAX LEVEL", True, YELLOW)
        surf.blit(ut, (100 - ut.get_width()//2, 195))
    else:
        pygame.draw.rect(surf, (80, 80, 80), (40, 180, 120, 35))
        ut = font.render(f"Need ${up_cost}", True, (150, 150, 150))
        surf.blit(ut, (100 - ut.get_width()//2, 190))
    pygame.draw.rect(surf, (160, 60, 60), (180, 180, 120, 35))
    dt = font.render("Delete", True, WHITE)
    surf.blit(dt, (240 - dt.get_width()//2, 190))
    pygame.draw.rect(surf, (180, 75, 75), (pw - 50, 10, 40, 22))
    xt = font.render("X", True, WHITE)
    surf.blit(xt, (pw - 37, 13))
    screen.blit(surf, (px, py))

def draw_level_complete():
    overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
    overlay.fill((0, 0, 0, 160))
    screen.blit(overlay, (0, 0))
    if current_level >= 9:
        txt = big_font.render("YOU WIN!", True, (100, 255, 100))
    else:
        txt = big_font.render(f"Level {current_level+1} Clear!", True, (100, 255, 100))
    screen.blit(txt, (WIDTH//2 - txt.get_width()//2, HEIGHT//2 - 80))
    sc = total_score + enemies_defeated * 10 + money
    st = font.render(f"Score: {sc}", True, YELLOW)
    screen.blit(st, (WIDTH//2 - st.get_width()//2, HEIGHT//2 - 20))
    if current_level >= 9:
        rt = font.render("Press R to Play Again", True, (200, 200, 255))
    else:
        rt = font.render("Press N for Next Level", True, (200, 200, 255))
    screen.blit(rt, (WIDTH//2 - rt.get_width()//2, HEIGHT//2 + 30))

def draw_game_over_screen():
    overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
    overlay.fill((0, 0, 0, 185))
    screen.blit(overlay, (0, 0))
    txt = big_font.render("Game Over! Radish eaten!", True, (250, 95, 95))
    screen.blit(txt, (WIDTH//2 - txt.get_width()//2, HEIGHT//2 - 60))
    rt = font.render("Press R to Restart Level", True, (195, 200, 250))
    screen.blit(rt, (WIDTH//2 - rt.get_width()//2, HEIGHT//2 + 10))
    lt = font.render("Press L for Level Select", True, (200, 220, 255))
    screen.blit(lt, (WIDTH//2 - lt.get_width()//2, HEIGHT//2 + 50))
    sc = total_score + enemies_defeated * 10 + money
    st = font.render(f"Score: {sc}", True, YELLOW)
    screen.blit(st, (WIDTH//2 - st.get_width()//2, HEIGHT//2 + 90))

def draw_start_screen():
    screen.fill((20, 38, 20))
    tt = title_font.render("Radish Defense", True, (95, 215, 95))
    screen.blit(tt, (WIDTH//2 - tt.get_width()//2, 120))
    # 萝卜
    pygame.draw.circle(screen, RADISH_BODY, (WIDTH//2, 280), 60)
    rd = (max(0, RADISH_BODY[0]-40), max(0, RADISH_BODY[1]-40), max(0, RADISH_BODY[2]-40))
    pygame.draw.ellipse(screen, rd, (WIDTH//2-40, 330, 80, 50))
    pygame.draw.circle(screen, WHITE, (WIDTH//2-20, 340), 15)
    pygame.draw.circle(screen, WHITE, (WIDTH//2+20, 345), 15)
    pygame.draw.circle(screen, BLACK, (WIDTH//2-20, 342), 7)
    pygame.draw.circle(screen, BLACK, (WIDTH//2+20, 352), 7)
    pygame.draw.arc(screen, (195, 75, 115), (WIDTH//2-20, 370, 40, 30), 0, math.pi, 5)
    pygame.draw.ellipse(screen, RADISH_LVS, (WIDTH//2-40, 268, 80, 60))
    ld = (max(0, RADISH_LVS[0]-20), max(0, RADISH_LVS[1]-20), max(0, RADISH_LVS[2]-20))
    pygame.draw.ellipse(screen, ld, (WIDTH//2-60, 298, 40, 40))
    pygame.draw.ellipse(screen, ld, (WIDTH//2+20, 328, 40, 40))
    # Start 按钮
    bx, by, bw, bh = WIDTH//2-100, 460, 200, 60
    br = pygame.Rect(bx, by, bw, bh)
    mp = pygame.mouse.get_pos()
    if br.collidepoint(mp):
        pygame.draw.rect(screen, BTN_HOVER, br)
    else:
        pygame.draw.rect(screen, BTN_COLOR, br)
    pygame.draw.rect(screen, BTN_HOVER, br, 3)
    stxt = big_font.render("Start", True, WHITE)
    screen.blit(stxt, (WIDTH//2 - stxt.get_width()//2, by + 13))
    # Select Level 按钮
    bx2, by2 = WIDTH//2-100, 540
    br2 = pygame.Rect(bx2, by2, 200, 50)
    if br2.collidepoint(mp):
        pygame.draw.rect(screen, (80, 120, 80), br2)
    else:
        pygame.draw.rect(screen, (60, 100, 60), br2)
    pygame.draw.rect(screen, (100, 180, 100), br2, 3)
    lt = font.render("Select Level", True, WHITE)
    screen.blit(lt, (WIDTH//2 - lt.get_width()//2, by2 + 15))
    tips = [
        "Defend the radish from 10 unique levels!",
        "Click a tower type, then click GREEN grid to place.",
        "RED grids = blocked.  GREEN = buildable.",
        "Survive all 10 levels to win!",
    ]
    for i, tip in enumerate(tips):
        t = font.render(tip, True, (195, 215, 195))
        screen.blit(t, (WIDTH//2 - t.get_width()//2, 610 + i * 26))

def draw_level_select():
    screen.fill((25, 30, 50))
    tt = big_font.render("Select Level", True, (100, 220, 100))
    screen.blit(tt, (WIDTH//2 - tt.get_width()//2, 50))
    st = font.render(f"Unlocked: {unlocked_levels}/10   Total Score: {total_score}", True, YELLOW)
    screen.blit(st, (WIDTH//2 - st.get_width()//2, 110))

    btn_w, btn_h = 160, 140
    cols_layout = 5
    gap_x, gap_y = 20, 25
    total_w = cols_layout * btn_w + (cols_layout - 1) * gap_x
    start_x = (WIDTH - total_w) // 2
    start_y = 170
    mp = pygame.mouse.get_pos()

    for i in range(10):
        row = i // cols_layout
        col = i % cols_layout
        bx = start_x + col * (btn_w + gap_x)
        by = start_y + row * (btn_h + gap_y)
        br = pygame.Rect(bx, by, btn_w, btn_h)
        is_unlocked = (i + 1) <= unlocked_levels
        is_current = i == current_level

        if not is_unlocked:
            pygame.draw.rect(screen, (50, 50, 60), br)
            pygame.draw.rect(screen, (80, 80, 90), br, 2)
            pygame.draw.rect(screen, (120, 120, 130), (bx + btn_w//2 - 15, by + 35, 30, 25))
            pygame.draw.arc(screen, (120, 120, 130), (bx + btn_w//2 - 15, by + 25, 30, 20), math.pi, 2*math.pi, 3)
            lt = font.render("???", True, (100, 100, 110))
            screen.blit(lt, (bx + btn_w//2 - lt.get_width()//2, by + 75))
        else:
            if is_current:
                base_color = (80, 140, 80)
                border_color = (100, 255, 100)
            elif br.collidepoint(mp):
                base_color = (70, 100, 140)
                border_color = (100, 180, 255)
            else:
                base_color = (55, 75, 110)
                border_color = (80, 130, 200)
            pygame.draw.rect(screen, base_color, br)
            pygame.draw.rect(screen, border_color, br, 3)
            num = big_font.render(f"{i+1}", True, WHITE)
            screen.blit(num, (bx + btn_w//2 - num.get_width()//2, by + 15))
            nm = font.render(LEVELS[i]["name"], True, (200, 220, 255))
            screen.blit(nm, (bx + btn_w//2 - nm.get_width()//2, by + 65))
            if i + 1 < unlocked_levels:
                cx = bx + btn_w//2
                cy = by + 105
                pygame.draw.polygon(screen, GOLD, [
                    (cx, cy-8), (cx+6, cy-2), (cx+4, cy+4), (cx+8, cy+6),
                    (cx, cy+2), (cx-8, cy+6), (cx-4, cy+4), (cx-6, cy-2)
                ])

    # Back 按钮
    back_r = pygame.Rect(WIDTH//2 - 80, HEIGHT - 70, 160, 45)
    if back_r.collidepoint(mp):
        pygame.draw.rect(screen, (120, 60, 60), back_r)
    else:
        pygame.draw.rect(screen, (90, 50, 50), back_r)
    pygame.draw.rect(screen, (180, 80, 80), back_r, 2)
    bt = font.render("Back to Title", True, WHITE)
    screen.blit(bt, (WIDTH//2 - bt.get_width()//2, HEIGHT - 58))

    ht = font.render("Click a level to play  |  Backspace to return", True, (150, 170, 200))
    screen.blit(ht, (WIDTH//2 - ht.get_width()//2, HEIGHT - 30))

# ===== 关卡管理 =====
def reset_level():
    global money, health, wave, enemies_defeated, towers, bullets, enemies, explosions
    global spawn_timer, tower_info_visible, info_tower, level_complete, game_over
    money = 150 + current_level * 30
    health = 10
    wave = 1
    enemies_defeated = 0
    towers = []
    bullets = []
    enemies = []
    explosions = []
    spawn_timer = 0
    tower_info_visible = False
    info_tower = None
    level_complete = False
    game_over = False

def load_level(idx):
    global current_level, path, scene
    current_level = idx
    path = LEVELS[current_level]["path"]
    reset_level()
    scene = "play"

def next_level():
    global current_level, total_score, path, unlocked_levels
    total_score += enemies_defeated * 10 + money
    current_level += 1
    if current_level >= 10:
        current_level = 9
    path = LEVELS[current_level]["path"]
    unlocked_levels = max(unlocked_levels, current_level + 1)
    reset_level()

def restart_game():
    global current_level, total_score, path, unlocked_levels
    current_level = 0
    total_score = 0
    unlocked_levels = 1
    path = LEVELS[0]["path"]
    reset_level()

# ===== 主循环 =====
running = True

while running:
    mouse_pos = pygame.mouse.get_pos()

    for ev in pygame.event.get():
        if ev.type == pygame.QUIT:
            running = False

        elif ev.type == pygame.MOUSEBUTTONDOWN:
            mx, my = ev.pos

            # === 标题界面 ===
            if scene == "start":
                bx, by, bw, bh = WIDTH//2-100, 460, 200, 60
                if bx <= mx <= bx+bw and by <= my <= by+bh:
                    load_level(0)
                    continue
                bx2, by2, bw2, bh2 = WIDTH//2-100, 540, 200, 50
                if bx2 <= mx <= bx2+bw2 and by2 <= my <= by2+bh2:
                    scene = "select"
                    continue

            # === 选关界面 ===
            elif scene == "select":
                btn_w, btn_h = 160, 140
                cols_layout = 5
                gap_x, gap_y = 20, 25
                total_w = cols_layout * btn_w + (cols_layout - 1) * gap_x
                start_x = (WIDTH - total_w) // 2
                start_y = 170
                for i in range(10):
                    row = i // cols_layout
                    col = i % cols_layout
                    bx = start_x + col * (btn_w + gap_x)
                    by = start_y + row * (btn_h + gap_y)
                    if bx <= mx <= bx+btn_w and by <= my <= by+btn_h:
                        if (i + 1) <= unlocked_levels:
                            load_level(i)
                        break
                back_r = pygame.Rect(WIDTH//2 - 80, HEIGHT - 70, 160, 45)
                if back_r.collidepoint(mx, my):
                    scene = "start"
                    continue

            # === 游戏中 ===
            elif scene == "play":
                if game_over:
                    continue
                if level_complete and current_level < 9:
                    next_level()
                    continue
                elif level_complete and current_level >= 9:
                    restart_game()
                    scene = "select"
                    continue

                # 关闭信息面板
                if tower_info_visible:
                    px, py = WIDTH//2-170, HEIGHT//2-140
                    if px+290 <= mx <= px+330 and py+10 <= my <= py+32:
                        tower_info_visible = False
                        continue
                    if px+40 <= mx <= px+160 and py+180 <= my <= py+215:
                        if info_tower and money >= info_tower.upgrade_cost() and info_tower.level < 5:
                            money -= info_tower.upgrade_cost()
                            info_tower.upgrade()
                        continue
                    if px+180 <= mx <= px+300 and py+180 <= my <= py+215:
                        refund = int(info_tower.total_invested * 0.6)
                        money += refund
                        towers.remove(info_tower)
                        tower_info_visible = False
                        info_tower = None
                        continue

                ui_y = HEIGHT - 150
                if my >= ui_y:
                    bw2, sp = 145, 18
                    sx = 20
                    for i, tid in enumerate(TOWER_TYPES.keys()):
                        bx2 = sx + i * (bw2 + sp)
                        by2 = ui_y + 42
                        if bx2 <= mx <= bx2+bw2 and by2 <= my <= by2+100:
                            if money >= TOWER_TYPES[tid]["cost"]:
                                selected_tower_type = tid
                            break
                    continue

                if selected_tower_type and my < ui_y:
                    grid = build_grid(towers)
                    cell = point_to_cell(mx, my)
                    if grid.get(cell) == "ok":
                        cx, cy = cell_center(*cell)
                        if not is_on_path(cx, cy) and not is_near_radish(cx, cy) and not is_near_tower(cx, cy, towers):
                            cost = TOWER_TYPES[selected_tower_type]["cost"]
                            if money >= cost:
                                towers.append(Tower(cx, cy, selected_tower_type))
                                money -= cost
                                selected_tower_type = None
                    for t in towers:
                        if math.sqrt((mx - t.x)**2 + (my - t.y)**2) < 22:
                            tower_info_visible = True
                            info_tower = t
                            break

        elif ev.type == pygame.KEYDOWN:
            if ev.key == pygame.K_r:
                if scene == "play" and game_over:
                    reset_level()
                elif scene == "play" and current_level >= 9 and level_complete:
                    restart_game()
                    scene = "select"
            if ev.key == pygame.K_n and scene == "play" and level_complete and current_level < 9:
                next_level()
            if ev.key == pygame.K_l and scene == "play" and game_over:
                scene = "select"
            if ev.key == pygame.K_ESCAPE:
                if scene == "play":
                    selected_tower_type = None
                    tower_info_visible = False
                elif scene == "select":
                    scene = "start"
                elif scene == "start":
                    running = False
            if ev.key == pygame.K_BACKSPACE and scene == "select":
                scene = "start"

    # ===== 更新逻辑 =====
    if scene == "start":
        draw_start_screen()
        pygame.display.flip()
        clock.tick(FPS)
        continue

    if scene == "select":
        draw_level_select()
        pygame.display.flip()
        clock.tick(FPS)
        continue

    # ===== 游戏进行中 =====
    if scene == "play" and not game_over and not level_complete:
        spawn_timer += 1
        max_enemies = 8 + wave * 2
        total_this_wave = wave * enemies_per_wave
        if spawn_timer >= spawn_delay and len(enemies) < max_enemies and enemies_defeated < total_this_wave:
            special_chance = min(0.3, 0.04 * wave)
            special = None
            if wave >= 7 and current_level >= 6 and random.random() < 0.15:
                special = "boss"
            elif wave >= 4 and random.random() < special_chance * 0.5:
                available = []
                if wave >= 4: available.append("stealth")
                if wave >= 5: available.append("bomber")
                if wave >= 6: available.append("flyer")
                if available:
                    special = random.choice(available)
            enemies.append(Enemy(path, wave, special))
            spawn_timer = 0

        for e in enemies[:]:
            reached = e.update()
            if reached:
                health -= 1
                enemies.remove(e)
                if health <= 0:
                    game_over = True
            elif e.health <= 0:
                if e.type == "bomber":
                    for t in towers[:]:
                        if math.sqrt((e.x - t.x)**2 + (e.y - t.y)**2) < e.bomb_range:
                            towers.remove(t)
                            money = max(0, money - 20)
                            explosions.append(Explosion(t.x, t.y, 40, ORANGE))
                    explosions.append(Explosion(e.x, e.y, 60, (255, 100, 0)))
                else:
                    explosions.append(Explosion(e.x, e.y))
                money += e.reward
                enemies_defeated += 1
                enemies.remove(e)

        for t in towers:
            b = t.update(enemies)
            if b:
                bullets.append(b)

        for b in bullets[:]:
            b.update()
            if not b.active and b in bullets:
                bullets.remove(b)

        for ex in explosions[:]:
            ex.update()
            if not ex.active:
                explosions.remove(ex)

        total_this_wave = wave * enemies_per_wave
        if enemies_defeated >= total_this_wave and len(enemies) == 0:
            wave += 1
            money += 80 + current_level * 20
            if wave > 5:
                level_complete = True
                unlocked_levels = max(unlocked_levels, current_level + 2)

    # ===== 绘制 =====
    screen.fill(BG)
    grid = build_grid(towers)
    draw_placement_grid(screen, grid, mouse_pos)
    draw_grass_bg()
    draw_path_line()
    draw_radish()

    if selected_tower_type:
        mx, my = mouse_pos
        cell = point_to_cell(mx, my)
        cx, cy = cell_center(*cell)
        gstatus = grid.get(cell, "no")
        if gstatus == "ok":
            r = TOWER_TYPES[selected_tower_type]["range"]
            s2 = pygame.Surface((r*2, r*2), pygame.SRCALPHA)
            pygame.draw.circle(s2, (80, 200, 80, 40), (r, r), r, 0)
            pygame.draw.circle(s2, (80, 255, 80, 100), (r, r), r, 2)
            screen.blit(s2, (cx - r, cy - r))
            tc = TOWER_TYPES[selected_tower_type]["color"]
            pygame.draw.circle(screen, tc, (cx, cy), 20)
            pygame.draw.circle(screen, (max(0,tc[0]-30),max(0,tc[1]-30),max(0,tc[2]-30)), (cx, cy), 15)
        else:
            pygame.draw.line(screen, (255, 60, 60), (cx-12, cy-12), (cx+12, cy+12), 4)
            pygame.draw.line(screen, (255, 60, 60), (cx+12, cy-12), (cx-12, cy+12), 4)

    for t in towers:
        t.draw(screen)
        if math.sqrt((mouse_pos[0]-t.x)**2 + (mouse_pos[1]-t.y)**2) < 25:
            s3 = pygame.Surface((t.range*2, t.range*2), pygame.SRCALPHA)
            pygame.draw.circle(s3, (80, 130, 255, 25), (t.range, t.range), t.range, 0)
            pygame.draw.circle(s3, (80, 160, 255, 80), (t.range, t.range), t.range, 1)
            screen.blit(s3, (t.x - t.range, t.y - t.range))

    for b in bullets:
        b.draw(screen)
    for e in enemies:
        e.draw(screen)
    for ex in explosions:
        ex.draw(screen)

    draw_ui()
    draw_tower_info_panel()

    if level_complete:
        draw_level_complete()
    elif game_over:
        draw_game_over_screen()

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

pygame.quit()
sys.exit()
