import tkinter as tk
from tkinter import ttk, messagebox
import random

# 地形定义
TERRAINS = {
    "grass":  {"color": "#7EC850", "name": "草地", "walkable": True},
    "water":  {"color": "#4A90D9", "name": "水域", "walkable": False},
    "sand":   {"color": "#E8D68E", "name": "沙地", "walkable": True},
    "forest": {"color": "#2D6A2E", "name": "森林", "walkable": True},
    "mountain": {"color": "#8B7355", "name": "山脉", "walkable": False},
    "road":   {"color": "#B0A090", "name": "道路", "walkable": True},
    "wall":   {"color": "#555555", "name": "墙壁", "walkable": False},
    "lava":   {"color": "#FF4500", "name": "熔岩", "walkable": False},
}

CELL_SIZE = 30
MAP_W, MAP_H = 25, 20


class MapEditor:
    def __init__(self, root):
        self.root = root
        self.root.title("🗺️ 二维地图编辑器")
        self.root.resizable(False, False)

        # 地图数据
        self.grid = [["grass" for _ in range(MAP_W)] for _ in range(MAP_H)]
        self.player_x, self.player_y = 0, 0
        self.current_terrain = "grass"
        self.drawing = False
        self.show_grid = True
        self.path = []

        self.build_ui()
        self.draw_map()

    def build_ui(self):
        # 顶部工具栏
        toolbar = tk.Frame(self.root, padx=5, pady=5)
        toolbar.pack(fill=tk.X)

        tk.Label(toolbar, text="画笔:", font=("微软雅黑", 10)).pack(side=tk.LEFT, padx=5)

        self.terrain_btns = {}
        for key, info in TERRAINS.items():
            btn = tk.Button(toolbar, text=info["name"], bg=info["color"],
                            font=("微软雅黑", 9), width=5,
                            command=lambda k=key: self.select_terrain(k))
            btn.pack(side=tk.LEFT, padx=2)
            self.terrain_btns[key] = btn

        self.terrain_btns["grass"].configure(relief=tk.SUNKEN)

        # 功能按钮
        func_frame = tk.Frame(self.root, padx=5, pady=3)
        func_frame.pack(fill=tk.X)

        tk.Button(func_frame, text="🎲 随机生成", font=("微软雅黑", 9),
                  command=self.random_generate).pack(side=tk.LEFT, padx=3)
        tk.Button(func_frame, text="🧹 清空地图", font=("微软雅黑", 9),
                  command=self.clear_map).pack(side=tk.LEFT, padx=3)
        tk.Button(func_frame, text="🔲 网格开关", font=("微软雅黑", 9),
                  command=self.toggle_grid).pack(side=tk.LEFT, padx=3)
        tk.Button(func_frame, text="🚶 寻路模式", font=("微软雅黑", 9),
                  command=self.find_path).pack(side=tk.LEFT, padx=3)

        self.status_label = tk.Label(func_frame, text="提示: 左键绘制 | 方向键移动角色 | 点击设置起点后点击终点寻路",
                                     font=("微软雅黑", 9), fg="#666")
        self.status_label.pack(side=tk.LEFT, padx=10)

        # Canvas 地图区域
        canvas_frame = tk.Frame(self.root, padx=5, pady=5)
        canvas_frame.pack()

        self.canvas = tk.Canvas(canvas_frame, width=MAP_W * CELL_SIZE, height=MAP_H * CELL_SIZE,
                                bg="white", highlightthickness=2, highlightbackground="#ccc")
        self.canvas.pack()

        # 绑定事件
        self.canvas.bind("<Button-1>", self.on_click)
        self.canvas.bind("<B1-Motion>", self.on_drag)
        self.canvas.bind("<ButtonRelease-1>", self.on_release)
        self.canvas.bind("<Button-3>", self.on_right_click)
        self.root.bind("<Key>", self.on_key)

        # 底部信息栏
        info_frame = tk.Frame(self.root, padx=5, pady=3)
        info_frame.pack(fill=tk.X)

        self.info_label = tk.Label(info_frame, text=f"地图大小: {MAP_W}×{MAP_H}  |  角色位置: (0, 0)",
                                   font=("微软雅黑", 9), fg="#333")
        self.info_label.pack(side=tk.LEFT)

        self.coord_label = tk.Label(info_frame, text="鼠标: -", font=("微软雅黑", 9), fg="#666")
        self.coord_label.pack(side=tk.RIGHT)

        self.canvas.bind("<Motion>", self.on_mouse_move)

    def select_terrain(self, terrain_key):
        self.current_terrain = terrain_key
        for key, btn in self.terrain_btns.items():
            btn.configure(relief=tk.RAISED if key != terrain_key else tk.SUNKEN)

    def draw_map(self):
        self.canvas.delete("all")

        # 绘制地形
        for y in range(MAP_H):
            for x in range(MAP_W):
                terrain = self.grid[y][x]
                color = TERRAINS[terrain]["color"]
                px, py = x * CELL_SIZE, y * CELL_SIZE
                self.canvas.create_rectangle(px, py, px + CELL_SIZE, py + CELL_SIZE,
                                             fill=color, outline="")

        # 绘制路径
        for px, py in self.path:
            x, y = px * CELL_SIZE, py * CELL_SIZE
            self.canvas.create_rectangle(x + 4, y + 4, x + CELL_SIZE - 4, y + CELL_SIZE - 4,
                                         fill="#FFD700", outline="#FFA500", width=2)

        # 绘制网格
        if self.show_grid:
            for x in range(MAP_W + 1):
                self.canvas.create_line(x * CELL_SIZE, 0, x * CELL_SIZE, MAP_H * CELL_SIZE,
                                        fill="#ddd", width=1)
            for y in range(MAP_H + 1):
                self.canvas.create_line(0, y * CELL_SIZE, MAP_W * CELL_SIZE, y * CELL_SIZE,
                                        fill="#ddd", width=1)

        # 绘制角色
        cx = self.player_x * CELL_SIZE + CELL_SIZE // 2
        cy = self.player_y * CELL_SIZE + CELL_SIZE // 2
        r = CELL_SIZE // 3
        self.canvas.create_oval(cx - r, cy - r, cx + r, cy + r,
                                fill="#FF3333", outline="#AA0000", width=2)
        # 角色眼睛
        self.canvas.create_oval(cx - 4, cy - 3, cx - 1, cy, fill="white", outline="")
        self.canvas.create_oval(cx + 1, cy - 3, cx + 4, cy, fill="white", outline="")

        self.info_label.configure(
            text=f"地图大小: {MAP_W}×{MAP_H}  |  角色位置: ({self.player_x}, {self.player_y})")

    def on_click(self, event):
        x, y = event.x // CELL_SIZE, event.y // CELL_SIZE
        if 0 <= x < MAP_W and 0 <= y < MAP_H:
            self.grid[y][x] = self.current_terrain
            self.path = []
            self.drawing = True
            self.draw_map()

    def on_drag(self, event):
        if self.drawing:
            x, y = event.x // CELL_SIZE, event.y // CELL_SIZE
            if 0 <= x < MAP_W and 0 <= y < MAP_H:
                self.grid[y][x] = self.current_terrain
                self.draw_map()

    def on_release(self, event):
        self.drawing = False

    def on_right_click(self, event):
        x, y = event.x // CELL_SIZE, event.y // CELL_SIZE
        if 0 <= x < MAP_W and 0 <= y < MAP_H:
            self.player_x, self.player_y = x, y
            self.path = []
            self.draw_map()

    def on_mouse_move(self, event):
        x, y = event.x // CELL_SIZE, event.y // CELL_SIZE
        if 0 <= x < MAP_W and 0 <= y < MAP_H:
            terrain = TERRAINS[self.grid[y][x]]
            self.coord_label.configure(text=f"鼠标: ({x}, {y}) {terrain['name']}")

    def on_key(self, event):
        dx, dy = 0, 0
        if event.keysym == "Up":
            dy = -1
        elif event.keysym == "Down":
            dy = 1
        elif event.keysym == "Left":
            dx = -1
        elif event.keysym == "Right":
            dx = 1
        else:
            return

        nx, ny = self.player_x + dx, self.player_y + dy
        if 0 <= nx < MAP_W and 0 <= ny < MAP_H:
            terrain = self.grid[ny][nx]
            if TERRAINS[terrain]["walkable"]:
                self.player_x, self.player_y = nx, ny
                self.path = []
                self.draw_map()
            else:
                self.status_label.configure(text=f"⚠️ {TERRAINS[terrain]['name']}不可通行！", fg="red")

    def random_generate(self):
        for y in range(MAP_H):
            for x in range(MAP_W):
                r = random.random()
                if r < 0.45:
                    self.grid[y][x] = "grass"
                elif r < 0.55:
                    self.grid[y][x] = "forest"
                elif r < 0.65:
                    self.grid[y][x] = "sand"
                elif r < 0.78:
                    self.grid[y][x] = "water"
                elif r < 0.88:
                    self.grid[y][x] = "mountain"
                else:
                    self.grid[y][x] = "road"

        # 确保角色位置可通行
        if not TERRAINS[self.grid[self.player_y][self.player_x]]["walkable"]:
            self.grid[self.player_y][self.player_x] = "grass"

        self.path = []
        self.draw_map()
        self.status_label.configure(text="✅ 已随机生成地图", fg="green")

    def clear_map(self):
        self.grid = [["grass" for _ in range(MAP_W)] for _ in range(MAP_H)]
        self.path = []
        self.draw_map()
        self.status_label.configure(text="✅ 地图已清空", fg="green")

    def toggle_grid(self):
        self.show_grid = not self.show_grid
        self.draw_map()

    def find_path(self):
        """BFS 寻路：从角色位置到鼠标最后点击位置"""
        # 找一个最远的可行走点作为终点
        end_x, end_y = None, None
        for y in range(MAP_H - 1, -1, -1):
            for x in range(MAP_W - 1, -1, -1):
                if TERRAINS[self.grid[y][x]]["walkable"] and (x, y) != (self.player_x, self.player_y):
                    end_x, end_y = x, y
                    break
            if end_x is not None:
                break

        if end_x is None:
            self.status_label.configure(text="⚠️ 找不到可行走的目标点", fg="red")
            return

        # BFS
        from collections import deque
        queue = deque([(self.player_x, self.player_y)])
        visited = {(self.player_x, self.player_y)}
        parent = {}

        while queue:
            cx, cy = queue.popleft()
            if (cx, cy) == (end_x, end_y):
                break
            for dx, dy in [(0, 1), (0, -1), (1, 0), (-1, 0)]:
                nx, ny = cx + dx, cy + dy
                if (0 <= nx < MAP_W and 0 <= ny < MAP_H
                        and (nx, ny) not in visited
                        and TERRAINS[self.grid[ny][nx]]["walkable"]):
                    visited.add((nx, ny))
                    parent[(nx, ny)] = (cx, cy)
                    queue.append((nx, ny))

        # 回溯路径
        if (end_x, end_y) in parent or (end_x, end_y) == (self.player_x, self.player_y):
            self.path = []
            cur = (end_x, end_y)
            while cur != (self.player_x, self.player_y):
                self.path.append(cur)
                cur = parent[cur]
            self.path.reverse()
            self.draw_map()
            self.status_label.configure(
                text=f"✅ 找到路径！起点({self.player_x},{self.player_y}) → 终点({end_x},{end_y})，步数: {len(self.path)}",
                fg="green")
        else:
            self.status_label.configure(text="⚠️ 无法到达目标点，路径被阻挡", fg="red")


if __name__ == "__main__":
    root = tk.Tk()
    app = MapEditor(root)
    root.mainloop()