#include "Game.h"
#include "Tank.h"
#include "UI.h"
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <random>
#include <unistd.h>

Game::Game() {
    std::srand(static_cast<unsigned>(std::time(nullptr)));
    playerBullets.resize(MAX_PLAYER_BULLETS);
    enemyBullets.resize(MAX_ENEMY_BULLETS);
    enemies.resize(ENEMIES_NUM);
}

Game::~Game() {
    delete render;
    delete assets;
    if (sdlRenderer) SDL_DestroyRenderer(sdlRenderer);
    if (window) SDL_DestroyWindow(window);
    Mix_CloseAudio();
    TTF_Quit();
    IMG_Quit();
    SDL_Quit();
}

bool Game::initSDL() {
    char* base = SDL_GetBasePath();
    if (base) { chdir(base); SDL_free(base); }

    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
        fprintf(stderr, "SDL init failed: %s\n", SDL_GetError());
        return false;
    }
    if (!(IMG_Init(IMG_INIT_PNG | IMG_INIT_JPG) & (IMG_INIT_PNG | IMG_INIT_JPG))) {
        fprintf(stderr, "SDL_image init failed: %s\n", IMG_GetError());
        return false;
    }
    if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0) {
        fprintf(stderr, "SDL_mixer init failed: %s\n", Mix_GetError());
        return false;
    }
    if (TTF_Init() < 0) {
        fprintf(stderr, "SDL_ttf init failed: %s\n", TTF_GetError());
        return false;
    }

    window = SDL_CreateWindow("纸牌坦克", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
                              WINDOW_W, WINDOW_H, SDL_WINDOW_SHOWN);
    if (!window) { fprintf(stderr, "Window failed: %s\n", SDL_GetError()); return false; }

    sdlRenderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    if (!sdlRenderer) { fprintf(stderr, "Renderer failed: %s\n", SDL_GetError()); return false; }

    assets = new AssetManager(sdlRenderer);
    render = new Renderer(sdlRenderer, assets);

    const char* fontPaths[] = {
        "/usr/share/fonts/wqy-microhei-fonts/wqy-microhei.ttc",
        "/usr/share/fonts/wqy-zenhei-fonts/wqy-zenhei.ttc",
        "/usr/share/fonts/google-noto-sans-cjk-vf-fonts/NotoSansCJK-VF.ttc",
        "/usr/share/fonts/google-noto-serif-cjk-vf-fonts/NotoSerifCJK-VF.ttc",
        nullptr
    };
    bool fontOk = false;
    for (int i = 0; fontPaths[i]; i++) {
        if (assets->loadFont(fontPaths[i], 30)) { fontOk = true; break; }
    }
    if (!fontOk) fprintf(stderr, "Warning: no Chinese font found\n");

    assets->loadBGM("music/bgm.wav");

    lastPlayerMove = lastPlayerShoot = lastEnemyMove = lastEnemyShoot = 0;
    lastBulletMove = lastEnemyBulletMove = 0;
    return true;
}

int Game::run() {
    if (!initSDL()) return -1;

    scene = Scene::MENU;
    SDL_Event e;
    while (running) {
        while (SDL_PollEvent(&e)) handleEvents(e);
        update();
        renderScene();
        SDL_Delay(16);
    }
    return 0;
}

// ------------------- event -------------------

void Game::handleEvents(SDL_Event& e) {
    if (e.type == SDL_QUIT) { running = false; return; }

    if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE) {
        switch (scene) {
            case Scene::LEVEL:
        case Scene::GAME:
            case Scene::WIN:
            case Scene::LOSE:
                scene = Scene::MENU;
                map.reset();
                break;
            default: break;
        }
        return;
    }

    if (e.type != SDL_MOUSEBUTTONDOWN) return;
    int mx = e.button.x, my = e.button.y;

    switch (scene) {
    case Scene::MENU:
        if (UI::hit(UI::BTN_START, mx, my))  { initGame(); scene = Scene::GAME; }
        if (UI::hit(UI::BTN_LEVEL, mx, my))  { scene = Scene::LEVEL; }
        if (UI::hit(UI::BTN_QUIT, mx, my))   { running = false; }
        break;
    case Scene::LEVEL:
        if (UI::hit(UI::BTN_EASY, mx, my)) {
            enemyCfg.hp = 5; enemyCfg.attack = 1; scene = Scene::MENU;
        }
        if (UI::hit(UI::BTN_MEDIUM, mx, my)) {
            enemyCfg.hp = 10; enemyCfg.attack = 2; scene = Scene::MENU;
        }
        if (UI::hit(UI::BTN_HARD, mx, my)) {
            enemyCfg.hp = 15; enemyCfg.attack = 3; scene = Scene::MENU;
        }
        break;
    case Scene::WIN:
    case Scene::LOSE:
        if (UI::hit(UI::BTN_BACK, mx, my)) scene = Scene::MENU;
        break;
    default: break;
    }
}

// ------------------- update -------------------

void Game::update() {
    if (scene != Scene::GAME) return;
    updateGame();
}

void Game::initGame() {
    map.reset();
    killCount = 0;

    player = Tank(5, 5);
    player.x = MAP_CELL_NUM / 2;
    player.y = MAP_CELL_NUM / 2;
    player.dir = UP;

    std::default_random_engine gen(std::random_device{}());
    std::uniform_int_distribution<int> dist(1, MAP_CELL_NUM - 2);

    for (auto& e : enemies) {
        do {
            e.x = dist(gen);
            e.y = dist(gen);
        } while (map.get(e.x, e.y) != BLANK);
        e.hp = enemyCfg.hp;
        e.attack = enemyCfg.attack;
        e.dir = LEFT;
        e.isTaken = false;
        map.set(e.x, e.y, BLUE_TANK);
    }

    for (auto& b : playerBullets) b.isLive = false;
    for (auto& b : enemyBullets) b.isLive = false;
}

bool Game::isWin() const {
    for (auto& e : enemies)
        if (e.hp > 0) return false;
    return player.hp > 0;
}

void Game::updateGame() {
    if (player.hp <= 0) { scene = Scene::LOSE; return; }
    if (isWin()) { scene = Scene::WIN; return; }

    Uint32 now = SDL_GetTicks();

    // --- 玩家移动 ---
    const Uint8* keys = SDL_GetKeyboardState(nullptr);
    bool moved = false;
    if (keys[SDL_SCANCODE_W] || keys[SDL_SCANCODE_UP])    { player.dir = UP;    moved = true; }
    else if (keys[SDL_SCANCODE_S] || keys[SDL_SCANCODE_DOWN]) { player.dir = DOWN;  moved = true; }
    else if (keys[SDL_SCANCODE_A] || keys[SDL_SCANCODE_LEFT]) { player.dir = LEFT;  moved = true; }
    else if (keys[SDL_SCANCODE_D] || keys[SDL_SCANCODE_RIGHT]){ player.dir = RIGHT; moved = true; }

    if (moved && now - lastPlayerMove >= 100) {
        lastPlayerMove = now;
        int tx = player.x + dx(player.dir);
        int ty = player.y + dy(player.dir);
        CELL_Type c = map.get(tx, ty);

        if (c == BLANK) {
            player.x = tx; player.y = ty;
        } else if (c == BULLET) {
            player.x = tx; player.y = ty;
            player.hp--;
            for (auto& b : enemyBullets) {
                if (b.isLive && b.x == tx && b.y == ty) { b.isLive = false; break; }
            }
        } else if (c == BLUE_DEAD_TANK) {
            player.x = tx; player.y = ty;
            player.attack++;
            if (player.hp < 5) player.hp++;
            for (auto& e : enemies) {
                if (e.hp <= 0 && !e.isTaken && e.x == tx && e.y == ty) {
                    e.isTaken = true; break;
                }
            }
        }
    }

    // --- 玩家射击 ---
    if (keys[SDL_SCANCODE_SPACE] && now - lastPlayerShoot >= 500) {
        lastPlayerShoot = now;
        for (auto& b : playerBullets) {
            if (!b.isLive) {
                b.fire(player.x, player.y, player.dir, player.attack);
                break;
            }
        }
    }

    // --- 敌人移动 ---
    if (now - lastEnemyMove >= 1000) {
        lastEnemyMove = now;
        for (auto& e : enemies) {
            if (e.hp <= 0) continue;
            Direction d = static_cast<Direction>(rand() % 4);
            e.dir = d;
            int tx = e.x + dx(d);
            int ty = e.y + dy(d);
            CELL_Type c = map.get(tx, ty);

            if (c == BLANK) {
                e.x = tx; e.y = ty;
            } else if (c == BULLET) {
                e.x = tx; e.y = ty;
                e.hp--;
                for (auto& pb : playerBullets) {
                    if (pb.isLive && pb.x == tx && pb.y == ty) { pb.isLive = false; break; }
                }
            }
        }
    }

    // --- 敌人射击 ---
    if (now - lastEnemyShoot >= 3000) {
        lastEnemyShoot = now;
        for (auto& e : enemies) {
            if (e.hp <= 0) continue;
            for (auto& b : enemyBullets) {
                if (!b.isLive) {
                    b.fire(e.x, e.y, e.dir, enemyCfg.attack);
                    break;
                }
            }
        }
    }

    // --- 玩家子弹移动 ---
    if (now - lastBulletMove >= 100) {
        lastBulletMove = now;
        for (auto& b : playerBullets) {
            if (!b.isLive) continue;
            CELL_Type c = b.peekAt(map.grid);

            if (c == BLANK) {
                b.step();
            } else if (c == WALL) {
                b.isLive = false;
            } else if (c == BLUE_TANK) {
                b.isLive = false;
                int tx = b.x + dx(b.dir), ty = b.y + dy(b.dir);
                for (auto& e : enemies) {
                    if (e.hp > 0 && e.x == tx && e.y == ty) { e.hp -= b.damage; break; }
                }
            } else {
                b.isLive = false;
            }
        }
    }

    // --- 敌人子弹移动 ---
    if (now - lastEnemyBulletMove >= 500) {
        lastEnemyBulletMove = now;
        for (auto& eb : enemyBullets) {
            if (!eb.isLive) continue;
            CELL_Type c = eb.peekAt(map.grid);

            if (c == BLANK) {
                eb.step();
            } else if (c == WALL) {
                eb.isLive = false;
            } else if (c == RED_TANK) {
                eb.isLive = false;
                player.hp -= eb.damage;
            } else {
                eb.step();
            }
        }
    }

    // --- 同步地图 ---
    map.reset();
    map.set(player.x, player.y, RED_TANK);
    for (auto& e : enemies) {
        if (e.hp > 0)
            map.set(e.x, e.y, BLUE_TANK);
        else if (!e.isTaken)
            map.set(e.x, e.y, BLUE_DEAD_TANK);
    }
}

// ------------------- render -------------------

void Game::renderScene() {
    render->clear();
    switch (scene) {
        case Scene::MENU:   renderMenu(); break;
        case Scene::LEVEL:  renderLevel(); break;
        case Scene::GAME:   renderGameView(); break;
        case Scene::WIN:    renderWin(); break;
        case Scene::LOSE:   renderLose(); break;
        default: break;
    }
    render->present();
}

static SDL_Color GRAY = {157, 157, 157, 255};

void Game::renderMenu() {
    render->drawImage("images/菜单界面.jpg", 0, 0, WINDOW_W, WINDOW_H);
    render->drawImage("images/开始游戏按键.jpg", UI::BTN_START.x, UI::BTN_START.y, UI::BTN_START.w, UI::BTN_START.h);
    render->drawImage("images/难度设置按键.jpg", UI::BTN_LEVEL.x, UI::BTN_LEVEL.y, UI::BTN_LEVEL.w, UI::BTN_LEVEL.h);
    render->drawImage("images/退出游戏按键.jpg", UI::BTN_QUIT.x, UI::BTN_QUIT.y, UI::BTN_QUIT.w, UI::BTN_QUIT.h);
}

void Game::renderLevel() {
    render->drawImage("images/游戏主界面背景.jpg", 0, 0, WINDOW_W, WINDOW_H);
    render->drawImage("images/简单难度.jpg", UI::BTN_EASY.x, UI::BTN_EASY.y, UI::BTN_EASY.w, UI::BTN_EASY.h);
    render->drawImage("images/中等难度.jpg", UI::BTN_MEDIUM.x, UI::BTN_MEDIUM.y, UI::BTN_MEDIUM.w, UI::BTN_MEDIUM.h);
    render->drawImage("images/困难难度.jpg", UI::BTN_HARD.x, UI::BTN_HARD.y, UI::BTN_HARD.w, UI::BTN_HARD.h);
}

void Game::renderGameView() {
    render->drawImage("images/游戏主界面背景.jpg", 0, 0, WINDOW_W, WINDOW_H);

    SDL_Texture* hpTex = assets->getTexture("images/red_hp_bar.jpg");
    for (int i = 0; i < player.hp; i++)
        render->drawTexture(hpTex, UI::HP_BAR_X + i * CELL_SIZE, UI::HP_BAR_Y, CELL_SIZE, CELL_SIZE);

    int dieNum = 0;
    for (auto& e : enemies) if (e.hp <= 0) dieNum++;
    render->drawText("杀敌：", 110, 660, GRAY);
    render->drawInt(dieNum, 185, 660, GRAY);
    render->drawText("/10", 210, 660, GRAY);
    std::string atk = "当前攻击力" + std::to_string(player.attack);
    render->drawText(atk, 325, 660, GRAY);

    SDL_Texture* wallTex = assets->getTexture("images/wall.jpg");
    for (int i = 0; i < MAP_CELL_NUM; i++)
        for (int j = 0; j < MAP_CELL_NUM; j++)
            if (map.grid[i][j] == WALL)
                render->drawTexture(wallTex, j * CELL_SIZE + X_OFFSET, i * CELL_SIZE + Y_OFFSET, CELL_SIZE, CELL_SIZE);

    // 子弹
    auto drawBullet = [&](Bullet& b) {
        if (!b.isLive) return;
        int sx = b.x * CELL_SIZE + X_OFFSET;
        int sy = b.y * CELL_SIZE + Y_OFFSET;
        bool horiz = (b.dir == LEFT || b.dir == RIGHT);
        int tx = horiz ? sx : sx + 10;
        int ty = horiz ? sy + 10 : sy;
        int bw = horiz ? CELL_SIZE / 2 : CELL_SIZE / 4;
        int bh = horiz ? CELL_SIZE / 4 : CELL_SIZE / 2;
        const char* img = nullptr;
        switch (b.dir) {
            case UP:    img = "images/B_UP_b.png"; break;
            case DOWN:  img = "images/B_DOWN_b.png"; break;
            case LEFT:  img = "images/B_LEFT_b.png"; break;
            case RIGHT: img = "images/B_RIGHT_b.png"; break;
        }
        SDL_Texture* tex = assets->getTexture(img);
        render->drawTexture(tex, tx, ty, bw, bh);
    };

    for (auto& b : playerBullets) drawBullet(b);
    for (auto& b : enemyBullets) drawBullet(b);

    // 坦克
    auto drawTank = [&](Tank& t, bool isPlayer) {
        int px = t.x * CELL_SIZE + X_OFFSET;
        int py = t.y * CELL_SIZE + Y_OFFSET;
        const char* img = nullptr;
        if (isPlayer) {
            switch (t.dir) {
                case UP: img = "images/red_up_b.png"; break;
                case DOWN: img = "images/red_down_b.png"; break;
                case LEFT: img = "images/red_left_b.png"; break;
                case RIGHT: img = "images/red_right_b.png"; break;
            }
        } else {
            switch (t.dir) {
                case UP: img = "images/blue_up_b.png"; break;
                case DOWN: img = "images/blue_down_b.png"; break;
                case LEFT: img = "images/blue_left_b.png"; break;
                case RIGHT: img = "images/blue_right_b.png"; break;
            }
        }
        render->drawTexture(assets->getTexture(img), px, py, CELL_SIZE, CELL_SIZE);
    };

    drawTank(player, true);
    for (auto& e : enemies) {
        if (e.isTaken) continue;
        if (e.hp > 0) drawTank(e, false);
        else render->drawTexture(assets->getTexture("images/dead_tank_b.png"),
                                 e.x * CELL_SIZE + X_OFFSET, e.y * CELL_SIZE + Y_OFFSET, CELL_SIZE, CELL_SIZE);
    }
}

void Game::renderWin() {
    render->drawImage("images/胜利.png", 0, 0, WINDOW_W, WINDOW_H);
    render->drawImage("images/返回按钮.jpg", UI::BTN_BACK.x, UI::BTN_BACK.y, UI::BTN_BACK.w, UI::BTN_BACK.h);
}

void Game::renderLose() {
    render->drawImage("images/失败.png", 0, 0, WINDOW_W, WINDOW_H);
    render->drawImage("images/返回按钮.jpg", UI::BTN_BACK.x, UI::BTN_BACK.y, UI::BTN_BACK.w, UI::BTN_BACK.h);
}
