import tkinter as tk
import math
import random
import json
import os
from dataclasses import dataclass, field
from typing import List, Dict, Any

# ========================
# 全局配置
# ========================
WIDTH, HEIGHT = 900, 600
TILE = 32
FPS = 60
MAP_W, MAP_H = 28, 18

# ========================
# 全局状态（✅ 全部提前定义）
# ========================
player_x = MAP_W // 2
player_y = MAP_H - 2
player_hp = 100
player_max_hp = 100
player_atk = 10
player_def = 5
player_exp = 0
player_lv = 1
player_gold = 100
player_stats = {"str": 5, "agi": 5, "vit": 5, "int": 5, "luk": 5}
stat_points = 0

inventory = []
equipment = {"weapon": None, "shield": None, "armor": None, "boots": None}
quests = {}
reputation = 0
messages = []
game_time = 0
paused = False
game_over = False
attack_cooldown = 0
current_screen = "game"

# ========================
# 数据
# ========================
monsters = []
chests = []
npcs = []
particles = []
damage_popups = []

map_data = [[0 for _ in range(MAP_W)] for _ in range(MAP_H)]

# ========================
# Tkinter
# ========================
root = tk.Tk()
root.title("⚔️ 像素勇者 RPG")
root.resizable(False, False)

canvas = tk.Canvas(root, width=WIDTH, height=HEIGHT, highlightthickness=0)
canvas.pack()

panel = tk.Frame(root)
panel.pack(fill="x")

info = tk.Label(panel, font=("Consolas", 10))
info.pack(side="left", padx=10)

# ========================
# 主题
# ========================
themes = {
    "🌲 经典像素": {"bg": "#2D5016", "fg": "#FFFFFF"},
    "🖤 暗黑地牢": {"bg": "#1A1A2E", "fg": "#CCCCCC"},
    "🍄 魔法森林": {"bg": "#1B4332", "fg": "#D8F3DC"},
    "🏜️ 沙漠遗迹": {"bg": "#C68642", "fg": "#3E2723"},
    "❄️ 冰封王座": {"bg": "#E3F2FD", "fg": "#0D47A1"},
    "🌋 火山熔洞": {"bg": "#6F1A07", "fg": "#FFBA08"},
}

def apply_theme(name):
    t = themes[name]
    root.configure(bg=t["bg"])
    panel.configure(bg=t["bg"])
    info.configure(bg=t["bg"], fg=t["fg"])
    canvas.configure(background=t["bg"])

# ========================
# 数据类
# ========================
@dataclass
class Monster:
    x: int
    y: int
    hp: int
    max_hp: int
    atk: int
    exp: int
    gold: int
    name: str
    color: str
    cd: int = 0

@dataclass
class Chest:
    x: int
    y: int
    opened: bool = False

@dataclass
class NPC:
    x: int
    y: int
    name: str
    quest_id: str
    color: str

@dataclass
class Item:
    name: str
    type: str
    stat: str
    value: int
    level: int
    color: str

# ========================
# 地图生成
# ========================
def generate_map():
    global map_data
    for y in range(MAP_H):
        for x in range(MAP_W):
            if x == 0 or y == 0 or x == MAP_W - 1 or y == MAP_H - 1:
                map_data[y][x] = 1
            elif random.random() < 0.05:
                map_data[y][x] = 2
            else:
                map_data[y][x] = 0

def spawn_entities():
    global monsters, chests, npcs
    monsters.clear()
    chests.clear()
    npcs.clear()

    types = [
        ("🟢史莱姆", 20, 3, 10, 5, "#4CAF50"),
        ("👺哥布林", 35, 6, 20, 10, "#8BC34A"),
        ("💀骷髅", 50, 9, 35, 15, "#BDBDBD"),
        ("👹兽人", 80, 12, 60, 25, "#F44336"),
        ("🧙巫师", 45, 15, 80, 30, "#9C27B0"),
    ]

    for _ in range(15):
        t = random.choice(types)
        monsters.append(Monster(
            random.randint(2, MAP_W - 3),
            random.randint(2, MAP_H - 3),
            t[1], t[1], t[2], t[3], t[4], t[0], t[5]
        ))

    for _ in range(5):
        chests.append(Chest(random.randint(2, MAP_W - 3),
                            random.randint(2, MAP_H - 3)))

    npcs.append(NPC(5, MAP_H - 3, "👴老村长", "quest1", "#FFD700"))
    npcs.append(NPC(MAP_W - 6, MAP_H - 3, "⚒️铁匠", "shop", "#78909C"))

# ========================
# 物品生成
# ========================
def create_item(level=1):
    names = ["铁剑", "钢剑", "圣剑", "木盾", "铁盾", "圣盾",
             "皮甲", "锁甲", "龙鳞甲", "布鞋", "铁靴", "风行靴"]
    types = ["weapon", "weapon", "weapon", "shield", "shield", "shield",
             "armor", "armor", "armor", "boots", "boots", "boots"]
    stats = ["atk", "atk", "atk", "def", "def", "def",
             "def", "def", "def", "def", "def", "spd"]
    colors = ["#BDBDBD", "#78909C", "#FFD700", "#8BC34A",
              "#607D8B", "#FFD700", "#795548", "#9E9E9E",
              "#F44336", "#E0E0E0", "#607D8B", "#00BCD4"]

    i = random.randint(0, len(names) - 1)
    return Item(names[i], types[i], stats[i],
                (i % 3 + 1) * level * 3,
                level, colors[i])

# ========================
# 任务
# ========================
def init_quests():
    global quests
    quests = {
        "quest1": {"name": "清理史莱姆", "target": 5, "progress": 0,
                   "reward_gold": 50, "reward_rep": 20, "done": False},
        "quest2": {"name": "击败骷髅兵", "target": 3, "progress": 0,
                   "reward_gold": 100, "reward_rep": 50, "done": False},
        "quest3": {"name": "击杀巨龙", "target": 1, "progress": 0,
                   "reward_gold": 500, "reward_rep": 200, "done": False},
    }

# ========================
# 绘制
# ========================
def draw_map():
    canvas.delete("map")
    for y in range(MAP_H):
        for x in range(MAP_W):
            cx = x * TILE
            cy = y * TILE
            if map_data[y][x] == 1:
                canvas.create_rectangle(cx, cy, cx + TILE, cy + TILE,
                                        fill="#5D4037", outline="#3E2723", tags="map")
            elif map_data[y][x] == 2:
                canvas.create_rectangle(cx, cy, cx + TILE, cy + TILE,
                                        fill="#388E3C", outline="#1B5E20", tags="map")
            else:
                canvas.create_rectangle(cx, cy, cx + TILE, cy + TILE,
                                        fill="#8BC34A", outline="#689F38", tags="map")

def draw_entities():
    canvas.delete("entity")
    for m in monsters:
        cx = m.x * TILE
        cy = m.y * TILE
        canvas.create_oval(cx + 4, cy + 4, cx + TILE - 4, cy + TILE - 4,
                           fill=m.color, outline="", tags="entity")
        canvas.create_text(cx + TILE // 2, cy - 6,
                           text=m.name, fill="#FFFFFF", font=("", 8), tags="entity")

    for c in chests:
        cx = c.x * TILE
        cy = c.y * TILE
        color = "#FFD700" if not c.opened else "#BDBDBD"
        canvas.create_rectangle(cx + 4, cy + 8, cx + TILE - 4, cy + TILE - 4,
                                fill=color, outline="#8B7500", tags="entity")

    for n in npcs:
        cx = n.x * TILE
        cy = n.y * TILE
        canvas.create_oval(cx + 4, cy + 4, cx + TILE - 4, cy + TILE - 4,
                           fill=n.color, outline="", tags="entity")
        canvas.create_text(cx + TILE // 2, cy - 6,
                           text=n.name, fill="#FFFFFF", font=("", 8), tags="entity")

def draw_player():
    canvas.delete("player")
    cx = player_x * TILE
    cy = player_y * TILE
    canvas.create_oval(cx + 4, cy + 4, cx + TILE - 4, cy + TILE - 4,
                       fill="#2196F3", outline="#0D47A1", width=2, tags="player")
    canvas.create_text(cx + TILE // 2, cy - 6,
                       text="勇者", fill="#FFFFFF", font=("", 8), tags="player")

def draw_ui():
    canvas.delete("ui")
    canvas.create_text(10, 10, anchor="nw",
                       text=f"❤️ {player_hp}/{player_max_hp}  ⚔️ {player_atk}  🛡️ {player_def}",
                       fill="#FFFFFF", font=("Consolas", 10), tags="ui")
    canvas.create_text(10, 30, anchor="nw",
                       text=f"🌟 Lv.{player_lv}  ✨ {player_exp}/100  💰 {player_gold}  🏆 {reputation}",
                       fill="#FFFFFF", font=("Consolas", 10), tags="ui")
    canvas.create_text(WIDTH - 10, 10, anchor="ne",
                       text=f"📍 {player_x},{player_y}",
                       fill="#FFFFFF", font=("Consolas", 10), tags="ui")

def draw_messages():
    canvas.delete("msg")
    for i, msg in enumerate(messages[-5:]):
        canvas.create_text(WIDTH // 2, HEIGHT - 60 - i * 18,
                           text=msg, fill="#FFFF00",
                           font=("Consolas", 9), tags="msg")

def draw_particles():
    canvas.delete("particle")
    for p in particles[:]:
        canvas.create_oval(p["x"], p["y"], p["x"] + 4, p["y"] + 4,
                           fill=p["c"], outline="", tags="particle")
        p["x"] += p["dx"]
        p["y"] += p["dy"]
        p["life"] -= 1
        if p["life"] <= 0:
            particles.remove(p)

def draw_damage():
    canvas.delete("dmg")
    for d in damage_popups[:]:
        canvas.create_text(d["x"], d["y"], text=d["text"],
                           fill=d["color"], font=("Consolas", 10, "bold"), tags="dmg")
        d["y"] -= 1
        d["life"] -= 1
        if d["life"] <= 0:
            damage_popups.remove(d)

# ========================
# 游戏逻辑
# ========================
def add_message(text):
    messages.append(text)
    if len(messages) > 10:
        messages.pop(0)

def add_damage(x, y, text, color="#FF0000"):
    damage_popups.append({"x": x * TILE + TILE // 2,
                          "y": y * TILE - 10,
                          "text": text,
                          "color": color,
                          "life": 30})

def move_player(dx, dy):
    global player_x, player_y
    nx = player_x + dx
    ny = player_y + dy
    if 0 <= nx < MAP_W and 0 <= ny < MAP_H and map_data[ny][nx] != 1:
        player_x = nx
        player_y = ny

def player_attack():
    global attack_cooldown, monsters, player_exp, player_gold, reputation
    if attack_cooldown > 0:
        return
    attack_cooldown = 20

    for m in monsters[:]:
        if abs(m.x - player_x) <= 1 and abs(m.y - player_y) <= 1:
            dmg = max(1, player_atk - random.randint(0, 3))
            m.hp -= dmg
            add_damage(m.x, m.y, f"-{dmg}")
            if m.hp <= 0:
                player_exp += m.exp
                player_gold += m.gold
                reputation += 1
                add_message(f"击杀{m.name}! +{m.exp}EXP +{m.gold}G")
                monsters.remove(m)
                check_level_up()
                update_quest_progress(m.name)
            break

def monster_ai():
    for m in monsters:
        if m.cd > 0:
            m.cd -= 1
            continue
        if abs(m.x - player_x) <= 1 and abs(m.y - player_y) <= 1:
            dmg = max(1, m.atk - player_def // 2)
            global player_hp
            player_hp -= dmg
            add_damage(player_x, player_y, f"-{dmg}", "#FF5252")
            m.cd = 30
            if player_hp <= 0:
                global game_over
                game_over = True
                add_message("💀 你死了! 按R重开")

def check_level_up():
    global player_exp, player_lv, player_max_hp, player_atk, player_def, stat_points
    if player_exp >= 100:
        player_lv += 1
        player_exp -= 100
        player_max_hp += 10
        player_atk += 2
        player_def += 1
        player_hp = player_max_hp
        stat_points += 3
        add_message(f"🎉 升级到 Lv.{player_lv}! 获得3点属性!")

def update_quest_progress(name):
    if "史莱姆" in name and not quests["quest1"]["done"]:
        quests["quest1"]["progress"] += 1
    elif "骷髅" in name and not quests["quest2"]["done"]:
        quests["quest2"]["progress"] += 1
    if quests["quest1"]["progress"] >= quests["quest1"]["target"]:
        complete_quest("quest1")

def complete_quest(qid):
    q = quests[qid]
    if q["done"]:
        return
    q["done"] = True
    global player_gold, reputation
    player_gold += q["reward_gold"]
    reputation += q["reward_rep"]
    add_message(f"✅ 完成任务{q['name']}! +{q['reward_gold']}G +{q['reward_rep']}声望")

def open_chest():
    for c in chests:
        if c.x == player_x and c.y == player_y and not c.opened:
            c.opened = True
            item = create_item(player_lv)
            inventory.append(item)
            add_message(f"🎁 获得{item.name}!")
            return

# ========================
# 场景绘制
# ========================
def draw_scene():
    draw_map()
    draw_entities()
    draw_player()
    draw_particles()
    draw_damage()
    draw_ui()
    draw_messages()

# ========================
# 游戏循环
# ========================
def game_loop():
    global attack_cooldown, game_time, paused, game_over

    if paused or game_over:
        return

    if attack_cooldown > 0:
        attack_cooldown -= 1

    monster_ai()
    game_time += 1
    draw_scene()

    if game_over:
        canvas.create_text(WIDTH // 2, HEIGHT // 2,
                           text="💀 GAME OVER\n按 R 重开",
                           fill="#F44336",
                           font=("Consolas", 28, "bold"))

    root.after(int(1000 / FPS), game_loop)

# ========================
# 控制
# ========================
def key_down(e):
    global paused, game_over, player_hp, player_max_hp
    global player_x, player_y, attack_cooldown

    if game_over:
        if e.keysym == "r":
            restart_game()
        return

    if e.keysym in ("w", "Up"):
        move_player(0, -1)
    if e.keysym in ("s", "Down"):
        move_player(0, 1)
    if e.keysym in ("a", "Left"):
        move_player(-1, 0)
    if e.keysym in ("d", "Right"):
        move_player(1, 0)
    if e.keysym == "j" or e.keysym == "space":
        player_attack()
    if e.keysym == "e":
        open_chest()
    if e.keysym == "p":
        paused = not paused
    if e.keysym == "r":
        restart_game()

def restart_game():
    global player_x, player_y, player_hp, player_max_hp
    global player_atk, player_def, player_exp, player_lv
    global player_gold, reputation, inventory, equipment
    global game_over, messages, stat_points

    player_x = MAP_W // 2
    player_y = MAP_H - 2
    player_hp = player_max_hp = 100
    player_atk = 10
    player_def = 5
    player_exp = 0
    player_lv = 1
    player_gold = 100
    reputation = 0
    inventory.clear()
    equipment = {k: None for k in equipment}
    game_over = False
    messages.clear()
    stat_points = 0
    spawn_entities()
    init_quests()
    add_message("🌟 新游戏开始!")

# ========================
# 绑定
# ========================
root.bind("<KeyPress>", key_down)

# ========================
# 启动
# ========================
generate_map()
spawn_entities()
init_quests()
add_message("🎮 WASD移动 J攻击 E开箱 P暂停 R重开")
apply_theme("🌲 经典像素")
game_loop()
root.mainloop()