import random
import tkinter as tk
from tkinter import messagebox

# 全局配置
MAP_W = 14
MAP_H = 9
CELL_SIZE = 50
PLAYER = 1
ENEMY = 2

# 地形配色与属性
TERRAIN = {
    "plains": {"def": 0, "move_cost": 1, "color": "#b9cc97", "name": "平原"},
    "mountain": {"def": 3, "move_cost": 2, "color": "#828282", "name": "山地"},
    "city": {"def": 4, "move_cost": 1, "color": "#c9b098", "name": "城镇"},
    "river": {"def": 1, "move_cost": 3, "color": "#68a8cc", "name": "河流"},
    "forest": {"def": 2, "move_cost": 1, "color": "#527d3e", "name": "密林"},
}
TERRAIN_KEYS = list(TERRAIN.keys())

# 兵种数据
UNIT_DATA = {
    "rifleman": {"hp": 100, "armor": 1, "atk": 25, "rng": 2, "move": 4, "type": "infantry", "name": "步兵"},
    "mg": {"hp": 110, "armor": 2, "atk": 35, "rng": 2, "move": 3, "type": "infantry", "name": "机枪组"},
    "sniper": {"hp": 80, "armor": 1, "atk": 70, "rng": 5, "move": 2, "type": "infantry", "name": "狙击手"},
    "tank": {"hp": 300, "armor": 8, "atk": 60, "rng": 3, "move": 5, "type": "armor", "name": "主战坦克"},
    "apc": {"hp": 180, "armor": 4, "atk": 40, "rng": 2, "move": 6, "type": "armor", "name": "装甲车"},
    "artillery": {"hp": 90, "armor": 1, "atk": 90, "rng": 6, "move": 2, "type": "artillery", "name": "牵引火炮"},
    "heli": {"hp": 160, "armor": 3, "atk": 55, "rng": 4, "move": 8, "type": "air", "name": "武装直升机"},
    "engineer": {"hp": 90, "armor": 1, "atk": 15, "rng": 1, "move": 3, "type": "infantry", "name": "工程兵"},
    "missile": {"hp": 120, "armor": 2, "atk": 100, "rng": 8, "move": 3, "type": "artillery", "name": "导弹发射车"},
    "commander": {"hp": 150, "armor": 3, "atk": 30, "rng": 2, "move": 2, "type": "infantry", "name": "前线指挥官"},
}

# 阵营配色
UNIT_COLORS = {
    "infantry": "#3080dd",
    "armor": "#225599",
    "artillery": "#662299",
    "air": "#00aaaa",
}
ENEMY_COLORS = {
    "infantry": "#dd3030",
    "armor": "#992222",
    "artillery": "#992266",
    "air": "#aa4400",
}

# 战役关卡
CAMPAIGNS = [
    {
        "title": "关卡1：边境摩擦",
        "ally": ["rifleman", "rifleman", "apc", "sniper"],
        "enemy": ["rifleman", "mg", "rifleman"],
        "win": "全歼所有敌军"
    },
    {
        "title": "关卡2：城镇攻防",
        "ally": ["tank", "rifleman", "heli", "artillery", "engineer"],
        "enemy": ["tank", "mg", "sniper", "apc", "commander"],
        "win": "清除全部敌方单位"
    },
    {
        "title": "关卡3：全域决战",
        "ally": ["tank", "tank", "missile", "heli", "sniper", "artillery", "rifleman", "commander"],
        "enemy": ["tank", "tank", "missile", "heli", "mg", "apc", "sniper", "commander"],
        "win": "歼灭敌方主力军团"
    }
]

# 地图格子类
class MapTile:
    def __init__(self, terrain_key):
        self.terrain = terrain_key
        self.unit = None

# 作战单位类
class CombatUnit:
    def __init__(self, uid, team):
        d = UNIT_DATA[uid]
        self.id = uid
        self.team = team
        self.name = d["name"]
        self.utype = d["type"]
        self.max_hp = d["hp"]
        self.hp = d["hp"]
        self.armor = d["armor"]
        self.atk = d["atk"]
        self.range = d["rng"]
        self.move_max = d["move"]
        self.x = 0
        self.y = 0
        self.acted = True

# 主游戏窗口
class WarGameGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("现代战棋兵棋游戏")
        self.root.geometry("1100x620")
        self.root.configure(bg="#1a1a1a")

        # 游戏数据
        self.map = []
        self.turn = 1
        self.stage_idx = 0
        self.all_units = []
        self.ally_units = []
        self.enemy_units = []
        self.selected = None
        self.mode = "move"
        self.move_zone = set()
        self.attack_zone = set()
        self.damage_text_list = []

        self.build_game_ui()
        self.load_level()
        self.render_all()

    # 游戏化UI面板
    def build_game_ui(self):
        # 战场画布
        self.canvas = tk.Canvas(self.root, bg="#0f0f0f", highlightthickness=0)
        self.canvas.place(x=10, y=10, width=MAP_W*CELL_SIZE, height=MAP_H*CELL_SIZE)
        self.canvas.bind("<Button-1>", self.click_map)

        # 右侧游戏信息面板
        panel = tk.Frame(self.root, bg="#282828")
        panel.place(x=MAP_W*CELL_SIZE+20, y=10, width=240, height=580)

        # 关卡、回合标题
        tk.Label(panel, text="现代陆战棋", font=("黑体",14,"bold"), fg="#ffdd44", bg="#282828").pack(pady=5)
        self.lb_stage = tk.Label(panel, font=("微软雅黑", 11), fg="white", bg="#282828", wraplength=220)
        self.lb_stage.pack(anchor="w", padx=5)
        self.lb_turn = tk.Label(panel, text=f"回合：{self.turn}", fg="#cccccc", bg="#282828")
        self.lb_turn.pack(anchor="w", padx=5, pady=2)
        self.lb_win = tk.Label(panel, wraplength=220, fg="#77dd77", bg="#282828")
        self.lb_win.pack(anchor="w", padx=5, pady=2)

        # 选中单位面板
        tk.Label(panel, text="选中单位", fg="#fff", bg="#282828").pack(anchor="w", padx=5, pady=(10,0))
        self.lb_sel = tk.Label(panel, text="无单位选中", fg="#ff6666", bg="#282828")
        self.lb_sel.pack(anchor="w", padx=5)

        # 模式切换按钮（游戏风格彩色按钮）
        frame_btn = tk.Frame(panel, bg="#282828")
        frame_btn.pack(pady=10)
        tk.Button(frame_btn, text="【移动】", width=8, bg="#38c938", fg="white",
                  command=lambda:self.set_mode("move")).grid(row=0,column=0,padx=3)
        tk.Button(frame_btn, text="【攻击】", width=8, bg="#e03030", fg="white",
                  command=lambda:self.set_mode("attack")).grid(row=0,column=1,padx=3)

        # 游戏功能按钮
        tk.Button(panel, text="结束我方回合", width=22, bg="#ffbb22", fg="black",
                  command=self.end_player_turn).pack(pady=3)
        tk.Button(panel, text="查看全军列表", width=22, bg="#444444", fg="white",
                  command=self.show_unit_list).pack(pady=2)
        tk.Button(panel, text="重新开始本关", width=22, bg="#555555", fg="white",
                  command=self.load_level).pack(pady=2)

        # 战斗日志
        tk.Label(panel, text="战斗记录", fg="white", bg="#282828").pack(anchor="w", padx=5, pady=(10,0))
        self.log_box = tk.Text(panel, width=27, height=12, bg="#121212", fg="#dddddd")
        self.log_box.pack(padx=5)

    def log(self, msg):
        self.log_box.insert(tk.END, msg + "\n")
        self.log_box.see(tk.END)
        self.root.update()

    def set_mode(self, m):
        self.mode = m
        self.refresh_range()
        self.render_all()
        if m == "move":
            self.log("▶ 切换移动模式，绿色格子可移动")
        else:
            self.log("▶ 切换攻击模式，红色格子可攻击")

    # 刷新移动/攻击范围
    def refresh_range(self):
        self.move_zone.clear()
        self.attack_zone.clear()
        if not self.selected or self.selected.acted:
            return
        u = self.selected
        for cy in range(MAP_H):
            for cx in range(MAP_W):
                dist = abs(cx - u.x) + abs(cy - u.y)
                if dist <= u.move_max:
                    self.move_zone.add((cx, cy))
                if dist <= u.range:
                    self.attack_zone.add((cx, cy))

    # 清空所有单位
    def clear_all_units(self):
        self.all_units.clear()
        self.ally_units.clear()
        self.enemy_units.clear()
        for y in range(MAP_H):
            for x in range(MAP_W):
                self.map[y][x].unit = None
        self.selected = None
        self.lb_sel.config(text="无单位选中", fg="#ff6666")
        self.move_zone.clear()
        self.attack_zone.clear()
        self.damage_text_list.clear()

    # 生成随机地形地图
    def generate_map(self):
        self.map = []
        for y in range(MAP_H):
            row = []
            for x in range(MAP_W):
                row.append(MapTile(random.choice(TERRAIN_KEYS)))
            self.map.append(row)

    # 部署关卡兵力
    def deploy_units(self):
        stage = CAMPAIGNS[self.stage_idx]
        self.clear_all_units()
        pos_y = 1
        for uid in stage["ally"]:
            unit = CombatUnit(uid, PLAYER)
            unit.x = 1
            unit.y = pos_y
            self.map[pos_y][1].unit = unit
            self.ally_units.append(unit)
            self.all_units.append(unit)
            pos_y += 1
        pos_y = 1
        for uid in stage["enemy"]:
            unit = CombatUnit(uid, ENEMY)
            unit.x = MAP_W - 2
            unit.y = pos_y
            self.map[pos_y][MAP_W-2].unit = unit
            self.enemy_units.append(unit)
            self.all_units.append(unit)
            pos_y += 1
        self.log(f"==== {stage['title']} 开始作战 ====")
        self.log(f"目标：{stage['win']}")

    # 加载关卡
    def load_level(self):
        self.turn = 1
        self.generate_map()
        self.deploy_units()
        self.update_text_info()
        self.render_all()

    def update_text_info(self):
        s = CAMPAIGNS[self.stage_idx]
        self.lb_stage.config(text=s["title"])
        self.lb_turn.config(text=f"回合：{self.turn}")
        self.lb_win.config(text=f"目标：{s['win']}")

    # 伤害计算
    def calc_damage(self, attacker, target):
        terrain_def = TERRAIN[self.map[target.y][target.x].terrain]["def"]
        dmg = attacker.atk - target.armor - terrain_def
        return max(5, dmg)

    # 渲染全部画面（游戏质感）
    def render_all(self):
        self.canvas.delete("all")
        # 绘制地形
        for y in range(MAP_H):
            for x in range(MAP_W):
                tile = self.map[y][x]
                cfg = TERRAIN[tile.terrain]
                x1 = x * CELL_SIZE
                y1 = y * CELL_SIZE
                x2 = x1 + CELL_SIZE
                y2 = y1 + CELL_SIZE
                self.canvas.create_rectangle(x1, y1, x2, y2, fill=cfg["color"], outline="#111111", width=1)

        # 绘制可移动/攻击区域
        if self.mode == "move":
            for (cx, cy) in self.move_zone:
                x1 = cx*CELL_SIZE
                y1 = cy*CELL_SIZE
                self.canvas.create_rectangle(x1,y1,x1+CELL_SIZE,y1+CELL_SIZE, fill="#20ff20", stipple="gray20")
        else:
            for (cx, cy) in self.attack_zone:
                x1 = cx*CELL_SIZE
                y1 = cy*CELL_SIZE
                self.canvas.create_rectangle(x1,y1,x1+CELL_SIZE,y1+CELL_SIZE, fill="#ff2020", stipple="gray20")

        # 绘制作战单位方块
        for unit in self.all_units:
            x1 = unit.x * CELL_SIZE + 8
            y1 = unit.y * CELL_SIZE + 8
            x2 = x1 + CELL_SIZE - 16
            y2 = y1 + CELL_SIZE - 16
            if unit.team == PLAYER:
                fill = UNIT_COLORS[unit.utype]
            else:
                fill = ENEMY_COLORS[unit.utype]
            # 选中单位金色发光边框
            if self.selected == unit:
                self.canvas.create_rectangle(x1-4,y1-4,x2+4,y2+4, outline="#ffdd00", width=4)
            self.canvas.create_rectangle(x1, y1, x2, y2, fill=fill, outline="#000000", width=2)
            # 血条红绿渐变
            hp_pct = unit.hp / unit.max_hp
            bar_h = 5
            self.canvas.create_rectangle(x1, y2+2, x2, y2+2+bar_h, fill="#222222")
            if hp_pct > 0.5:
                bar_color = "#22dd22"
            elif hp_pct > 0.25:
                bar_color = "#dddd22"
            else:
                bar_color = "#dd2222"
            self.canvas.create_rectangle(x1, y2+2, x1+(x2-x1)*hp_pct, y2+2+bar_h, fill=bar_color)

        # 绘制伤害飘字
        for data in self.damage_text_list:
            x, y, dmg, tick = data
            self.canvas.create_text(x, y-tick*3, text=f"-{dmg}", fill="#ff2222", font=("黑体",16,"bold"))
        # 自动清除飘字
        self.damage_text_list = [(x,y,d,t+1) for x,y,d,t in self.damage_text_list if t < 20]

    # 鼠标点击地图逻辑
    def click_map(self, event):
        cx = event.x // CELL_SIZE
        cy = event.y // CELL_SIZE
        if not (0 <= cx < MAP_W and 0 <= cy < MAP_H):
            return
        tile = self.map[cy][cx]

        # 未选中单位，点击己方单位选中
        if self.selected is None:
            if tile.unit and tile.unit.team == PLAYER:
                self.selected = tile.unit
                self.lb_sel.config(text=f"{self.selected.name} HP:{self.selected.hp}/{self.selected.max_hp}", fg="#44ff44")
                self.refresh_range()
                self.render_all()
            return

        sel = self.selected
        if self.mode == "move":
            # 移动逻辑
            if tile.unit is not None:
                self.log("× 格子有单位，无法移动")
                return
            if sel.acted:
                self.log("× 该单位本回合已行动")
                return
            if (cx, cy) not in self.move_zone:
                self.log("× 超出移动距离")
                return
            self.map[sel.y][sel.x].unit = None
            sel.x, sel.y = cx, cy
            self.map[cy][cx].unit = sel
            sel.acted = True
            self.log(f"✓ {sel.name} 移动至({cx},{cy})")
            self.selected = None
            self.lb_sel.config(text="无单位选中", fg="#ff6666")
        else:
            # 攻击逻辑
            if not tile.unit or tile.unit.team == PLAYER:
                self.log("× 攻击模式只能点敌方单位")
                return
            if sel.acted:
                self.log("× 该单位本回合已行动")
                return
            if (cx, cy) not in self.attack_zone:
                self.log("× 超出攻击射程")
                return
            target = tile.unit
            dmg = self.calc_damage(sel, target)
            target.hp -= dmg
            sel.acted = True
            # 添加伤害飘字
            draw_x = target.x * CELL_SIZE + CELL_SIZE//2
            draw_y = target.y * CELL_SIZE + CELL_SIZE//2
            self.damage_text_list.append([draw_x, draw_y, dmg, 0])
            self.log(f"⚔ {sel.name}攻击{target.name}，造成{dmg}伤害，剩余HP{target.hp}")
            # 单位阵亡
            if target.hp <= 0:
                self.map[target.y][target.x].unit = None
                self.enemy_units.remove(target)
                self.all_units.remove(target)
                self.log(f"💀 敌方{target.name} 被击杀！")
            self.selected = None
            self.lb_sel.config(text="无单位选中", fg="#ff6666")

        self.refresh_range()
        self.render_all()
        self.check_win_lose()

    # 结束我方回合，AI自动行动
    def end_player_turn(self):
        self.selected = None
        self.lb_sel.config(text="无单位选中", fg="#ff6666")
        self.move_zone.clear()
        self.attack_zone.clear()
        self.log("———— 敌方AI行动阶段 ————")
        self.root.update()

        for e_unit in self.enemy_units:
            e_unit.acted = False
        ai_copy = self.enemy_units.copy()
        for enemy in ai_copy:
            if enemy not in self.enemy_units or enemy.acted:
                continue
            best_target = None
            min_dist = 999
            for ally in self.ally_units:
                dist = abs(enemy.x - ally.x) + abs(enemy.y - ally.y)
                if dist <= enemy.range and dist < min_dist:
                    min_dist = dist
                    best_target = ally
            if best_target:
                dmg = self.calc_damage(enemy, best_target)
                best_target.hp -= dmg
                enemy.acted = True
                draw_x = best_target.x * CELL_SIZE + CELL_SIZE//2
                draw_y = best_target.y * CELL_SIZE + CELL_SIZE//2
                self.damage_text_list.append([draw_x, draw_y, dmg, 0])
                self.log(f"敌方{enemy.name}攻击我方{best_target.name}，造成{dmg}伤害")
                if best_target.hp <= 0:
                    self.map[best_target.y][best_target.x].unit = None
                    self.ally_units.remove(best_target)
                    self.all_units.remove(best_target)
                    self.log(f"💥 我方{best_target.name} 阵亡！")
            else:
                nx = max(0, enemy.x - 2)
                if self.map[enemy.y][nx].unit is None:
                    self.map[enemy.y][enemy.x].unit = None
                    enemy.x = nx
                    self.map[enemy.y][nx].unit = enemy
                enemy.acted = True

        self.turn += 1
        for a in self.ally_units:
            a.acted = False
        self.update_text_info()
        self.log(f"==== 第{self.turn}回合，我方行动 ====")
        self.render_all()
        self.check_win_lose()

    # 胜负判定弹窗
    def check_win_lose(self):
        if len(self.ally_units) == 0:
            messagebox.showerror("战役失败", "全军覆没，任务失败！\n点击确认重新挑战本关")
            self.load_level()
            return
        if len(self.enemy_units) == 0:
            if self.stage_idx + 1 >= len(CAMPAIGNS):
                messagebox.showinfo("全局通关！", "恭喜你通关全部关卡，获得最终胜利！")
                self.root.destroy()
            else:
                messagebox.showinfo("关卡通关", "本关敌人全部肃清，进入下一关卡！")
                self.stage_idx += 1
                self.load_level()

    # 全军列表弹窗
    def show_unit_list(self):
        text = "【我方部队】\n"
        for idx, u in enumerate(self.ally_units):
            text += f"{idx+1}. {u.name} HP:{u.hp}/{u.max_hp} 坐标({u.x},{u.y})\n"
        text += "\n【敌方部队】\n"
        for idx, u in enumerate(self.enemy_units):
            text += f"{idx+1}. {u.name} HP:{u.hp}/{u.max_hp} 坐标({u.x},{u.y})\n"
        messagebox.showinfo("全军兵力一览", text)

if __name__ == "__main__":
    win = tk.Tk()
    game = WarGameGUI(win)
    win.mainloop()