import pygame
import random
import sys
import json
import os

# ===================== 基础初始化 =====================
pygame.init()
WIDTH, HEIGHT = 950, 650
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("深度挖矿模拟器【完整版】")
clock = pygame.time.Clock()
FPS = 60

# 颜色
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
BROWN = (101, 67, 33)
GRAY = (120, 120, 120)
GOLD_COLOR = (255, 215, 0)
RED = (220, 30, 30)
GREEN = (40, 180, 40)
BLUE = (60, 120, 220)
PURPLE = (160, 60, 220)
DARK_GREY = (40, 40, 50)

# 字体
try:
    font_small = pygame.font.SysFont("simhei", 18)
    font_mid = pygame.font.SysFont("simhei", 24)
    font_big = pygame.font.SysFont("simhei", 30)
except:
    font_small = pygame.font.SysFont("arial", 18)
    font_mid = pygame.font.SysFont("arial", 24)
    font_big = pygame.font.SysFont("arial", 30)

# ======== 数据配置 ========
ORE_DATA = [
    {"name": "石头", "hp": 2, "price": 1, "color": GRAY, "min_layer": 1},
    {"name": "铜矿", "hp": 4, "price": 3, "color": (180, 110, 60), "min_layer": 1},
    {"name": "铁矿", "hp": 6, "price": 6, "color": (160, 160, 160), "min_layer": 2},
    {"name": "金矿", "hp": 10, "price": 15, "color": GOLD_COLOR, "min_layer": 3},
    {"name": "钻石", "hp": 16, "price": 40, "color": (80, 200, 255), "min_layer": 4},
]

PICKAXE_LIST = [
    {"name": "木镐", "dmg": 1, "price": 0},
    {"name": "石镐", "dmg": 2, "price": 80},
    {"name": "铁镐", "dmg": 3, "price": 250},
    {"name": "金镐", "dmg": 5, "price": 600},
    {"name": "钻石镐", "dmg": 8, "price": 1500},
]

SHOP_POTION = {"name": "体力药水", "recover": 40, "price": 30}
SAVE_FILE = "mine_save.json"

# ==================== 游戏数据 ====================
def init_new_game():
    data = {
        "gold": 50,
        "stamina": 100,
        "max_stamina": 100,
        "current_pickaxe": 0,  # 索引对应镐子
        "layer": 1,  # 当前矿层
        "inventory": {"石头": 0, "铜矿": 0, "铁矿": 0, "金矿": 0, "钻石": 0},
        "potion_count": 2
    }
    return data

def save_game(save_data):
    with open(SAVE_FILE, "w", encoding="utf-8") as f:
        json.dump(save_data, f, ensure_ascii=False, indent=2)

def load_game():
    if os.path.exists(SAVE_FILE):
        try:
            with open(SAVE_FILE, "r", encoding="utf-8") as f:
                return json.load(f)
        except:
            return init_new_game()
    return init_new_game()

game_data = load_game()
ores = []
monsters = []
event_msg = ""
event_timer = 0

# ==================== 矿石类 ====================
class Ore:
    def __init__(self, layer):
        self.x = random.randint(40, WIDTH - 200)
        self.y = random.randint(130, HEIGHT - 140)
        # 根据层数筛选可用矿石
        avail_ores = [o for o in ORE_DATA if o["min_layer"] <= layer]
        weights = []
        for o in avail_ores:
            if o["name"] == "石头":
                w = max(50 - layer*6, 10)
            elif o["name"] == "铜矿":
                w = max(35 - layer*4, 8)
            elif o["name"] == "铁矿":
                w = 15 + layer*2
            elif o["name"] == "金矿":
                w = 5 + layer*3
            elif o["name"] == "钻石":
                w = max(layer - 2, 1)
            else:
                w = 5
            weights.append(w)
        ore_type = random.choices(avail_ores, weights=weights)[0]
        self.name = ore_type["name"]
        self.max_hp = ore_type["hp"]
        self.hp = self.max_hp
        self.price = ore_type["price"]
        self.color = ore_type["color"]
        self.size = 58

    def draw(self):
        pygame.draw.ellipse(screen, self.color, (self.x, self.y, self.size, self.size))
        pygame.draw.ellipse(screen, BLACK, (self.x, self.y, self.size, self.size), 2)
        bar_w = self.size
        bar_h = 6
        fill = bar_w * (self.hp / self.max_hp)
        pygame.draw.rect(screen, RED, (self.x, self.y - 12, bar_w, bar_h))
        pygame.draw.rect(screen, GREEN, (self.x, self.y - 12, fill, bar_h))
        txt = font_small.render(self.name, True, WHITE)
        screen.blit(txt, (self.x + 4, self.y + self.size + 2))

    def hit(self, damage):
        self.hp -= damage
        return self.hp <= 0

    def is_click(self, mx, my):
        return self.x <= mx <= self.x + self.size and self.y <= my <= self.y + self.size

# ==================== 怪物类 ====================
class Monster:
    def __init__(self, layer):
        self.x = random.randint(60, WIDTH - 220)
        self.y = random.randint(140, HEIGHT - 160)
        self.size = 45
        self.speed = 0.3 + layer * 0.12
        self.damage = 3 + layer
        self.color = (180, 20, 60)

    def update(self, mouse_x, mouse_y):
        dx = mouse_x - (self.x + self.size/2)
        dy = mouse_y - (self.y + self.size/2)
        dist = (dx**2 + dy**2)**0.5
        if dist > 5:
            self.x += dx / dist * self.speed
            self.y += dy / dist * self.speed

    def draw(self):
        pygame.draw.circle(screen, self.color, (int(self.x+self.size/2), int(self.y+self.size/2)), self.size//2)
        pygame.draw.circle(screen, BLACK, (int(self.x+self.size/2), int(self.y+self.size/2)), self.size//2, 2)

    def check_touch(self, mx, my):
        cx = self.x + self.size/2
        cy = self.y + self.size/2
        dis = ((mx-cx)**2 + (my-cy)**2)**0.5
        return dis < self.size//2

# ==================== 生成矿区 ====================
def spawn_area():
    global ores, monsters
    layer = game_data["layer"]
    ores = [Ore(layer) for _ in range(11 + layer*2)]
    monsters = []
    # 层数越高怪物越多
    monster_num = max(0, layer - 1)
    for _ in range(monster_num):
        monsters.append(Monster(layer))

# ==================== 随机事件 ====================
def trigger_random_event():
    global event_msg, event_timer
    roll = random.randint(1, 100)
    if roll < 12:
        # 塌方扣体力
        lose = random.randint(8,20)
        game_data["stamina"] = max(0, game_data["stamina"] - lose)
        event_msg = f"⚠️矿道塌方！体力-{lose}"
    elif roll < 24:
        # 幸运宝箱
        gold_get = random.randint(40,120)
        game_data["gold"] += gold_get
        event_msg = f"🎁发现宝箱！金币+{gold_get}"
    elif roll < 36:
        # 天然矿脉，生成额外钻石
        ores.append(Ore(game_data["layer"]))
        ores.append(Ore(game_data["layer"]))
        event_msg = "💎发现天然富矿！新增矿石"
    elif roll < 45:
        game_data["stamina"] = min(game_data["max_stamina"], game_data["stamina"] + 25)
        event_msg = "🍃清新气流，体力恢复25"
    else:
        return
    event_timer = 180

# ==================== 商店功能 ====================
def open_shop():
    running_shop = True
    while running_shop:
        screen.fill(DARK_GREY)
        title = font_big.render("🏪矿工商店", True, GOLD_COLOR)
        screen.blit(title, (WIDTH//2 - 100, 40))

        y = 110
        # 镐子列表
        screen.blit(font_mid.render("=== 镐子 ===", True, WHITE), (120, y))
        y += 40
        for idx, pick in enumerate(PICKAXE_LIST):
            if idx <= game_data["current_pickaxe"]:
                text = f"{pick['name']} 【已拥有】伤害:{pick['dmg']}"
                col = GREEN
            else:
                text = f"{pick['name']} | 伤害:{pick['dmg']} | 价格:{pick['price']}"
                col = WHITE
            ren = font_mid.render(text, True, col)
            rect = pygame.Rect(120, y, 450, 36)
            pygame.draw.rect(screen, (60,60,75), rect)
            screen.blit(ren, (130, y+4))
            # 点击购买
            mx, my = pygame.mouse.get_pos()
            for ev in pygame.event.get():
                if ev.type == pygame.QUIT:
                    save_game(game_data)
                    pygame.quit()
                    sys.exit()
                if ev.type == pygame.MOUSEBUTTONDOWN:
                    if rect.collidepoint(mx, my) and idx > game_data["current_pickaxe"]:
                        if game_data["gold"] >= pick["price"]:
                            game_data["gold"] -= pick["price"]
                            game_data["current_pickaxe"] = idx
                if ev.type == pygame.KEYDOWN and ev.key == pygame.K_ESCAPE:
                    running_shop = False
            y += 46

        # 体力药水
        potion_y = y + 30
        pot_rect = pygame.Rect(120, potion_y, 450, 36)
        pygame.draw.rect(screen, (60,60,75), pot_rect)
        pot_text = f"{SHOP_POTION['name']} 恢复{SHOP_POTION['recover']}体力 | {SHOP_POTION['price']}金币 | 持有:{game_data['potion_count']}"
        screen.blit(font_mid.render(pot_text, True, WHITE), (130, potion_y+4))
        if pot_rect.collidepoint(mx, my):
            for ev in pygame.event.get():
                if ev.type == pygame.MOUSEBUTTONDOWN:
                    if game_data["gold"] >= SHOP_POTION["price"]:
                        game_data["gold"] -= SHOP_POTION["price"]
                        game_data["potion_count"] += 1

        exit_text = font_small.render("按 ESC 关闭商店", True, RED)
        screen.blit(exit_text, (WIDTH//2 - 80, HEIGHT-60))
        pygame.display.flip()
        clock.tick(FPS)

# ==================== 主游戏初始化 ====================
spawn_area()
current_damage = PICKAXE_LIST[game_data["current_pickaxe"]]["dmg"]

# ==================== 主循环 ====================
running = True
while running:
    mx, my = pygame.mouse.get_pos()
    screen.fill((30,30,42))
    current_pick = PICKAXE_LIST[game_data["current_pickaxe"]]

    # 事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            save_game(game_data)
            running = False

        if event.type == pygame.MOUSEBUTTONDOWN:
            if game_data["stamina"] > 0:
                # 挖掘矿石
                for ore in ores[:]:
                    if ore.is_click(mx, my):
                        game_data["stamina"] -= 1
                        if ore.hit(current_pick["dmg"]):
                            game_data["inventory"][ore.name] += 1
                            ores.remove(ore)
                            # 随机事件触发
                            if random.random() < 0.08:
                                trigger_random_event()

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                # 使用药水
                if game_data["potion_count"] > 0:
                    game_data["potion_count"] -= 1
                    game_data["stamina"] = min(game_data["max_stamina"], game_data["stamina"] + SHOP_POTION["recover"])
            if event.key == pygame.K_s:
                # 出售全部矿石
                for ore_info in ORE_DATA:
                    name = ore_info["name"]
                    cnt = game_data["inventory"][name]
                    game_data["gold"] += cnt * ore_info["price"]
                for k in game_data["inventory"]:
                    game_data["inventory"][k] = 0
            if event.key == pygame.K_r:
                spawn_area()
            if event.key == pygame.K_b:
                open_shop()
            if event.key == pygame.K_DOWN:
                # 下一层
                if len(ores) == 0:
                    game_data["layer"] += 1
                    spawn_area()
            if event.key == pygame.K_UP:
                # 上一层
                if game_data["layer"] > 1 and len(ores) == 0:
                    game_data["layer"] -= 1
                    spawn_area()

    # 怪物更新 & 碰撞扣体力
    for m in monsters[:]:
        m.update(mx, my)
        if m.check_touch(mx, my) and pygame.mouse.get_pressed()[0]:
            game_data["stamina"] -= m.damage * 0.02
            if game_data["stamina"] <= 0:
                game_data["stamina"] = 0

    # 事件消息倒计时
    if event_timer > 0:
        event_timer -= 1
        msg_render = font_mid.render(event_msg, True, GOLD_COLOR)
        screen.blit(msg_render, (WIDTH//2 - 180, 105))

    # ========== 顶部UI ==========
    pygame.draw.rect(screen, BROWN, (0, 0, WIDTH, 100))
    screen.blit(font_mid.render(f"💰金币:{game_data['gold']}", True, WHITE), (20,12))
    screen.blit(font_mid.render(f"⛏️{current_pick['name']}(伤害{current_pick['dmg']})", True, WHITE), (160,12))
    screen.blit(font_mid.render(f"📍矿层:{game_data['layer']}", True, WHITE), (380,12))
    screen.blit(font_mid.render(f"🧪药水:{game_data['potion_count']}", True, WHITE), (500,12))

    # 体力条
    screen.blit(font_mid.render("体力:", True, WHITE), (620,12))
    pygame.draw.rect(screen, BLACK, (680,15, 160,22))
    fill_w = 156 * (game_data["stamina"] / game_data["max_stamina"])
    pygame.draw.rect(screen, BLUE, (682,17, fill_w, 18))
    screen.blit(font_small.render(f"{int(game_data['stamina'])}/{game_data['max_stamina']}", True, WHITE), (700,14))

    # 操作提示
    hint = font_small.render("B商店 | S出售 | R刷新 | 空格使用药水 | 矿石清空后↑↓切换矿层", True, WHITE)
    screen.blit(hint, (20, 65))

    # 绘制矿石怪物
    for ore in ores:
        ore.draw()
    for m in monsters:
        m.draw()

    # 右侧背包面板
    bag_x = WIDTH - 170
    pygame.draw.rect(screen, (50,50,65), (bag_x, 110, 160, 450))
    pygame.draw.rect(screen, WHITE, (bag_x,110,160,450), 2)
    screen.blit(font_mid.render("📦背包", True, WHITE), (bag_x+45,120))
    y_off = 160
    for name, num in game_data["inventory"].items():
        txt = font_small.render(f"{name}: {num}", True, WHITE)
        screen.blit(txt, (bag_x+15, y_off))
        y_off += 36

    # 矿区清空提示
    if len(ores) == 0:
        tip = font_big.render("矿区清空！↑↓切换矿层 / R刷新", True, GOLD_COLOR)
        screen.blit(tip, (WIDTH//2 - 260, HEIGHT//2))

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

# 退出自动保存
save_game(game_data)
pygame.quit()
sys.exit()