Tool full options

Tool khoáng

// ==UserScript==
// @name         Tool full options
// @namespace    http://tampermonkey.net/
// @version      0.3.2
// @description  Tool khoáng
// @author       Optimized by KeshiNguyen
// @match        *://*/*
// @run-at       document-idle
// @grant        GM.xmlHttpRequest
// @grant        GM_notification
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// @connect      discord.com
// ==/UserScript==
    'use strict';

(function() {
    //Check update
    function checkForUpdates() {
        const currentVersion = GM_info.script.version;
        const lastVersion = GM_getValue('lastVersion', '');

        if (lastVersion && lastVersion !== currentVersion) {
            // Hiển thị thông báo cập nhật
            GM_notification({
                text: `Script đã được cập nhật từ ${lastVersion} lên ${currentVersion}. Nhấp để xem thay đổi.`,
                title: 'Cập nhật Script',
                image: 'https://greasyfork.org/assets/blacklogo96-ea600e6a6acf4efc2c543cc4a6f5c6c3506a567aeda3e3b8c347c2baab4d2f90.png',
                onclick: function() {
                    // Mở trang changelog hoặc Greasy Fork
                    window.open('https://greasyfork.org/en/scripts/549540-tool-full-options/versions', '_blank');
                }
            });

            // Ghi log vào console
            console.log(`[Script Update] Đã cập nhật từ ${lastVersion} lên ${currentVersion}`);
        }

        // Lưu phiên bản hiện tại
        GM_setValue('lastVersion', currentVersion);
    }
    checkForUpdates();
    const isGameDomain = () => {
        return /cmangax\d+\.com|cnovel/.test(location.hostname);
    };

    if (!isGameDomain()) return;
    let target = "";
    let reload = 10 * 1000;
    const URL = {
        ENERGY: (character_id) => `/api/character_energy_mine?character=${character_id}`,
        HMK_AREA: (area) => `/api/score_list?type=battle_mine&area=${area}`,
        OTHER: (id) => `api/get_data_by_id?table=game_character&data=info,other&id=${id}`,
    };
    let diffTimeServer = 2 * 60 * 60; //lệch 2 giờ

    // Thêm CSS cho giao diện
    GM_addStyle(`
        .keshi-miner-ui {
            position: fixed;
            bottom: 140px;
            left: 20px;
            z-index: 10000;
            font-family: Arial, sans-serif;
        }

        .keshi-miner-button {
            background: linear-gradient(135deg, #4ecca3 0%, #2a9d8f 100%);
            color: white;
            border: none;
            border-radius: 50%;
            width: 60px;
            height: 60px;
            font-size: 16px;
            font-weight: bold;
            cursor: pointer;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
            transition: all 0.3s ease;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .keshi-miner-button:hover {
            transform: scale(1.05);
            box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
        }

        .keshi-miner-menu {
            position: absolute;
            bottom: 70px;
            left: 0;
            min-width: 800px;
            background: #16213e;
            border-radius: 10px;
            box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5);
            overflow: hidden;
            display: none;
            min-height: 1000px;
            font-size: 18px;
        }

        .keshi-miner-menu.active {
            display: block;
        }

        .keshi-menu-header {
            padding: 15px;
            background: #0f3460;
            text-align: center;
            font-weight: bold;
            font-size: 18px;
            color: #4ecca3;
        }

        .keshi-tabs {
            display: flex;
            background: #0f3460;
        }

        .keshi-tab {
            flex: 1;
            padding: 12px;
            text-align: center;
            cursor: pointer;
            transition: background 0.3s;
            color: white;
        }

        .keshi-tab.active {
            background: #4ecca3;
            color: #16213e;
            font-weight: bold;
        }

        .keshi-tab-content {
            padding: 15px;
            overflow-y: auto;
            color: white;
        }

        .keshi-tab-pane {
            display: none;
        }

        .keshi-tab-pane.active {
            display: block;
        }

        .keshi-sub-tabs {
            display: flex;
            margin-bottom: 15px;
            background: #1a1a2e;
            border-radius: 5px;
            overflow: hidden;
        }

        .keshi-sub-tab {
            flex: 1;
            padding: 8px;
            text-align: center;
            cursor: pointer;
            transition: background 0.3s;
            color: white;
            min-heigth: 500px;
        }

        .keshi-sub-tab.active {
            background: #4ecca3;
            color: #16213e;
            font-weight: bold;
        }

        .keshi-form-group {
            margin-bottom: 15px;
        }

        .keshi-form-group label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
            color: #4ecca3;
        }

        .keshi-form-group input, .keshi-form-group select {
            width: 100%;
            padding: 10px;
            border: none;
            border-radius: 5px;
            background: #1a1a2e;
            color: white;
            border: 1px solid #0f3460;
        }

        .keshi-btn {
            padding: 10px 15px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-weight: bold;
            transition: all 0.3s;
        }

        .keshi-btn-primary {
            background: #4ecca3;
            color: #16213e;
        }

        .keshi-btn-primary:hover {
            background: #2a9d8f;
        }

        .keshi-btn-danger {
            background: #e94560;
            color: white;
        }

        .keshi-btn-danger:hover {
            background: #c1334d;
        }

        .keshi-target-list {
            margin-top: 20px;
            overflow-y: auto;
        }

        .keshi-target-item {
            padding: 10px;
            background: #1a1a2e;
            border-radius: 5px;
            margin-bottom: 10px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            border-left: 3px solid #4ecca3;
            color: white;
        }

        .keshi-target-info {
            flex: 1;
        }

        .keshi-target-actions {
            display: flex;
            gap: 5px;
        }

        .keshi-miner-list {
            margin-top: 15px;
            max-height: 800px;
            overflow-y: auto;
        }

        .keshi-miner-item {
            padding: 12px;
            background: #1a1a2e;
            border-radius: 5px;
            margin-bottom: 10px;
            border-left: 3px solid #0f3460;
            color: white;
            font-size: 18px;
        }

        .keshi-miner-header {
            display: flex;
            justify-content: space-between;
            margin-bottom: 8px;
        }

        .keshi-miner-area {
            font-weight: bold;
            color: #4ecca3;
        }

        .keshi-miner-rare {
            color: #e94560;
        }

        .keshi-miner-details {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 10px;
            font-size: 0.9rem;
        }

        .keshi-status-indicator {
            display: inline-block;
            width: 10px;
            height: 10px;
            border-radius: 50%;
            margin-right: 5px;
        }

        .keshi-status-active {
            background: #4ecca3;
        }

        .keshi-status-inactive {
            background: #e94560;
        }

        .keshi-mining-controls {
            display: flex;
            gap: 10px;
            margin-bottom: 15px;
        }

        .keshi-stats-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 15px;
            margin-top: 15px;
        }

        .keshi-stat-card {
            background: #1a1a2e;
            border-radius: 8px;
            padding: 15px;
            text-align: center;
            border-left: 4px solid #4ecca3;
        }

        .keshi-stat-value {
            font-size: 24px;
            font-weight: bold;
            color: #4ecca3;
            margin: 10px 0;
        }

        .keshi-stat-label {
            font-size: 14px;
            color: #cfd0d4;
        }

        .keshi-clear-data {
            margin-top: 20px;
            text-align: center;
        }
        .keshi-modal {
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: rgba(0, 0, 0, 0.7);
        display: flex;
        justify-content: center;
        align-items: center;
        z-index: 10001;
    }

    .keshi-stat-item {
        display: grid;
        grid-template-columns: 250px 1fr;
        align-items: center;
        gap: 10px;
        font-size: 22px;
        padding: 12px;
        margin: 4px 0;
        border-left: 6px solid transparent;
        background: #1a1a1a;
        border-radius: 6px;
    }

    .keshi-stat-item span {
        font-weight: bold;
    }

    /* màu theo trạng thái */
    .keshi-stat-item.success {
        border-left-color: #4CAF50; /* xanh lá */
    }
    .keshi-stat-item.fail {
        border-left-color: #f44336; /* đỏ */
    }
    .keshi-stat-item.register {
        border-left-color: #ffffff; /* trắng */
    }
    .keshi-modal-content {
        background: #16213e;
        border-radius: 10px;
        padding: 20px;
        width: 400px;
        max-width: 90%;
        box-shadow: 0 5px 20px rgba(0, 0, 0, 0.5);
    }
    .keshi-detail-miner {
        display: flex;
        justify-content: space-between;
        padding: 15px;
    }

    .keshi-modal-header {
        font-size: 18px;
        font-weight: bold;
        color: #4ecca3;
        margin-bottom: 15px;
        text-align: center;
    }

    .keshi-character-info {
        display: flex;
        margin-bottom: 20px;
        align-items: center;
    }

    .keshi-character-avatar {
        width: 80px;
        height: 80px;
        border-radius: 50%;
        margin-right: 15px;
        border: 3px solid #4ecca3;
    }

    .keshi-character-details {
        flex: 1;
    }

    .keshi-character-name {
        font-size: 16px;
        font-weight: bold;
        color: white;
        margin-bottom: 5px;
    }

    .keshi-character-guild {
        font-size: 14px;
        color: #cfd0d4;
        margin-bottom: 5px;
    }

    .keshi-character-id {
        font-size: 14px;
        color: #cfd0d4;
    }

    .keshi-modal-actions {
        display: flex;
        justify-content: center;
        gap: 10px;
    }

    .keshi-loading {
        text-align: center;
        padding: 20px;
        color: #4ecca3;
    }

    .battle-detail {

    }
    `);
    const RARE = {
        4: { name: '🔥 Truyền Thuyết', src: '/assets/img/level/icon/mine/4.png',color: '#ff0000' },
        3: { name: '📜 Sử Thi', src: '/assets/img/level/icon/mine/3.png', color: '#c700ff' },
        2: { name: '🛡️ Hiếm', src: '/assets/img/level/icon/mine/2.png', color: '#0099ff' },
        1: { name: '⚔️ Thường', src: '/assets/img/level/icon/mine/1.png', color: '#666666' },
    };

    const ACTION = {
        attack: { name: "Tấn công"},
        isAttacked: { name: "Bị tấn công"},
        buy: { name: "Mua"},
        read: { name: "Đọc truyện"},
        sign: { name: "Tham gia"},
        donate: { name: "Cống"},
    }

    const COLOR_CODE = {
        success: {color: "#4CAF50"},
        fail: {color: "#f44336"},
        register: {color: "#ffffff"},
    }

    const waitForGameKeys = (timeout = 5000) => {
        return new Promise((resolve, reject) => {
            const start = Date.now();
            const check = () => {
                const scripts = document.getElementsByTagName('script');
                for (const script of scripts) {
                    const player_id = script.textContent.match(/my_character\s*=\s*['"]?(\d+)['"]?/);
                    const token_user = script.textContent.match(/token_user\s*=\s*['"]?(\d+)['"]?/);
                    const token_character = script.textContent.match(/token_character\s*=\s*['"]?([a-zA-Z0-9]+)['"]?/);
                    if (player_id && token_character) {
                        return resolve({
                            player_id: parseInt(player_id[1], 10),
                            token_character: token_character[1],
                            token_user: parseInt(token_user[1], 10),
                        });
                    }
                }

                if (Date.now() - start > timeout) {
                    return reject("Không tìm thấy thông tin player/token trong thời gian cho phép.");
                }

                setTimeout(check, 200);
            };
            check();
        });
    };

    const getTime = (time) => {
        const options = {
            timeZone: 'Asia/Ho_Chi_Minh', // Múi giờ Việt Nam
            day: '2-digit',
            month: '2-digit',
            year: 'numeric',
            hour: '2-digit',
            minute: '2-digit',
            second: '2-digit',
            hour12: false
        };
        return time.toLocaleString('vi-VN', options)
    }

    function deepMerge(target, source) {
        for (const key in source) {
            if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) {
                if (!target[key] || typeof target[key] !== "object") {
                    target[key] = {};
                }
                deepMerge(target[key], source[key])
            } else {
                target[key] = source[key]
            }
        }
        return target;
    }

    class MinerUI {
        constructor() {
            if (!window.MiningManager) {
                let _targets = [];
                window.MiningManager = {
                    get targets() {
                        return _targets;
                    },
                    set targets(val) {
                        _targets = val;
                        //console.log("[MiningManager] cập nhật targets:", _targets);
                        if (window.minerUIInstance) {
                            window.minerUIInstance.renderMiningList();
                        }
                    },
                    me: []
                };
            }

            if (!window.SManager) {
                window.SManager = {
                    save(key, data) {
                        try {
                            localStorage.setItem(`keshi_miner_${key}`, JSON.stringify(data));
                            return true;
                        } catch (e) {
                            console.error('Lỗi khi lưu dữ liệu:', e);
                            return false;
                        }
                    },
                    load(key) {
                        try {
                            const data = localStorage.getItem(`keshi_miner_${key}`);
                            return data ? JSON.parse(data) : null;
                        } catch (e) {
                            console.error('Lỗi khi tải dữ liệu:', e);
                            return null;
                        }
                    },
                    remove(key) {
                        try {
                            localStorage.removeItem(`keshi_miner_${key}`);
                            return true;
                        } catch (e) {
                            console.error('Lỗi khi xóa dữ liệu:', e);
                            return false;
                        }
                    }
                };
            }

            if (!window.AccountManager) {
                let _accounts = window.SManager.load("accounts") ?? [];
                /*
                account: {
                     info: {id, name, level, guild, legendary},
                     activity: {
                          daily: {dungeon: {turn: ?? / max_turn}, dragon_tomb: {sign_at, total: 10000}, word: {event: ??/3, total_sign: ??/20, repair: ,detail_turn: [{time: {start_at, end_at}, treasure: {gold, item:[]}, repair:{fee} }], legendary, guild_transport: {sign_at, upgrade, total},treasure_find: {turn: ??/max_turn, detail: {turn_1: {sign_at}, turn_2: {}}} },
                          weekly: {battle_doa, pet_champion, battle_champion, black_prison, guild_battle}
                     },
                     mine: {}
                }
                */
                window.AccountManager = {
                    accounts: _accounts,
                    get accounts() {
                        return _accounts;
                    },
                    loadAccounts() {
                        const accountsSaved = window.SManager.load("acccounts") ?? [];
                        if (Array.isArray(accountsSaved)) _accounts = accountsSaved;
                        return _accounts;
                    },
                    addAccount(account) {
                        const exists = _accounts.some(acc => acc.info?.id === account?.info?.id);
                        if (!exists) {
                            _accounts.push(account);
                            this.save();
                        }
                        return null
                    },
                    updateAccount(account_id, field_update={}) {
                        const idx = _accounts.findIndex(acc => acc.info?.id === account_id)
                        if (idx===-1) {
                            console.warn(`[AccountManager] Account ${account_id} not found`);
                            return null;
                        }
                        _accounts[idx] = deepMerge(_accounts[idx], field_update)
                        this.save();
                        return _accounts[idx]
                    },
                    removeAccount(account_id) {
                        const before = _accounts.length;
                        _accounts = _accounts.filter(acc => acc.info?.id !== account_id);
                        if (_accounts.length < before) {
                            this.save();
                            return true;
                        }
                        return true;
                    },
                    save() {
                        window.SManager.save("accounts", _accounts);
                        return true;
                    }
                }
            }

            if (!window.TargetManager) {
                const baseManager = {
                    targets: [],
                    loadTargets() {
                        const saved = window.SManager.load("targets");
                        this.targets = saved || [];
                        console.log("load target from localStorage")
                        return this.targets;
                    },
                    saveTargets() {
                        return window.SManager.save("targets", this.targets);
                    },
                    updateProcess(target_id) {
                        const target = this.targets.find(t => t.id == target_id)
                        if (!target) return false;
                        target.processing = !target.processing;
                        this.saveTargets();
                        return target.processing;
                    },
                    addTarget(target) {
                        if (this.targets.some(t => t.id === target.id)) return false;
                        target.addedAt = new Date().toISOString();
                        this.targets.push(target);
                        return this.saveTargets();
                    },
                    removeTarget(targetId) {
                        this.targets = this.targets.filter(t => t.id !== targetId);
                        return this.saveTargets();
                    },
                    clearAllTargets() {
                        this.targets = [];
                        return this.saveTargets();
                    }
                }
                window.TargetManager = new Proxy(baseManager, {
                    set(target, prop, value) {
                        if (prop === "targets") {
                            const old = target[prop];
                            if (JSON.stringify(old) !== JSON.stringify(value)){
                                target[prop] = value;
                                //console.log("[TargetManager] targets thay đổi:", value);
                                target.saveTargets();

                                if (window.autoMiner) window.autoMiner.init();
                                if (window.minerUIInstance) window.minerUIInstance.renderTargetList();
                            }
                        }
                        target[prop] = value;
                        return true;
                    }
                })
            }

            if (!window.StatsManager) {
                let _stats = window.SManager.load("stats") ?? {};
                const todayKey = getTime(new Date()).split(" ")[1];
                _stats[todayKey] ??= [];
                window.StatsManager = {
                    get stats() { return _stats; },
                    set stats(val) {
                        if (val && typeof val === 'object') {
                            _stats = val;
                            window.SManager.save('stats', _stats);
                            if (window.minerUIInstance && typeof window.minerUIInstance.updateStatsDisplay === 'function') {
                                window.minerUIInstance.updateStatsDisplay();
                            }
                        } else {
                            console.error("StatsManager: stats phải là object theo ngày");
                        }
                    },
                    loadStats() {
                        const saved = window.SManager.load('stats');
                        if (saved && typeof saved === 'object') _stats = saved;
                        return _stats;
                    },
                    getToday() {
                        const statDate = getTime(new Date()).split(' ')[1]
                        return this.get(statDate)
                    },
                    add(stat) {
                        //stat {time, action, map, detail, target, status, other, }
                        if(!stat || typeof stat !== 'object' || !stat.time) {
                            alert("Lỗi dữ liệu đầu vào")
                            return false
                        };
                        // Check phạm vi thời gian (không quá 10 phút trước và không vượt tương lai)
                        if ((new Date().getTime() - stat.time > 10 * 60 * 1000) || stat?.time > new Date().getTime()) {
                            alert("Thời gian không thuộc phạm vi cho phép")
                            return false;
                        }
                        const statDate = getTime(new Date(stat.time)).split(' ')[1]
                        //test
                        if (!_stats[statDate]) {
                            _stats[statDate] = [];
                        }

                        _stats[statDate].push(stat)
                        window.SManager.save("stats", _stats)
                        console.log("Đã lưu thành công 1 stat mới:::", stat);
                        console.log(window.StatsManager.loadStats())
                        if (window.minerUIInstance && typeof window.minerUIInstance.updateStatsDisplay === 'function') {
                            window.minerUIInstance.updateStatsDisplay(stat);
                        }
                        return true
                    },
                    get(dateKey) {
                        return _stats[dateKey] || null;
                    }
                };
                window.SManager.save("stats", _stats);
            }

            this.miningManager = window.MiningManager;
            this.targetManager = window.TargetManager;
            this.statManager = window.StatsManager;
            this.accountManager = window.AccountManager;
            window.minerUIInstance = this;

            // Tạo container UI
            this.minerUI = document.createElement('div');
            this.minerUI.className = 'keshi-miner-ui';
            document.body.appendChild(this.minerUI);

            this.initUI();
            //console.log("DEBUG StorageManager:", window.StorageManager);
            //console.log("DEBUG typeof load:", typeof window.StorageManager.load);

            this.targetManager.loadTargets();
            this.statManager.loadStats();
            this.statManager.getToday();

            this.renderTargetList();
            this.renderMiningList();
            this.renderStatsList({ mode: "all" });
            this.renderStatsList({ mode: "today" });
            this.renderCloneList();

        }

        initUI() {
            this.minerUI.innerHTML = `
            <button class="keshi-miner-button" id="keshiMinerToggle">Tool</button>
            <div class="keshi-miner-menu" id="keshiMinerMenu">
                <div class="keshi-tabs">
                    <div class="keshi-tab active" data-tab="status">Trang thái</div>
                    <div class="keshi-tab" data-tab="dig">Dí khoáng</div>
                    <div class="keshi-tab" data-tab="clone">Clone</div>
                    <div class="keshi-tab" data-tab="stats">Thống kê</div>
                    <div class="keshi-tab" data-tab="settings">Cài đặt</div>
                </div>

                <div class="keshi-tab-content">
                    <div class="keshi-tab-pane" id="keshi-status-pane">
                        <div class="keshi-sub-tabs">
                            <div class="keshi-sub-tab active" data-subtab="activity">Hoạt động</div>
                            <div class="keshi-sub-tab" data-subtab="word">Cửu giới</div>
                            <div class="keshi-sub-tab" data-subtab="mine">Khoáng</div>
                        </div>

                        <div class="keshi-sub-tab-content">
                            <div class="keshi-tab-pane active" id="keshi-activity-pane">
                                <div class="keshi-miner-list" id="keshi-activity-list"></div>
                            </div>

                            <div class="keshi-tab-pane" id="keshi-word-pane">
                                <div class="keshi-miner-list" id="keshi-word-list"></div>
                            </div>

                            <div class="keshi-tab-pane" id="keshi-mine-pane">
                                <div class="keshi-miner-list" id="keshi-mine-list"></div>
                            </div>
                        </div>
                    </div>
                    <div class="keshi-tab-pane" id="keshi-clone-pane">
                        <div class="keshi-sub-tabs">
                            <div class="keshi-sub-tab active" data-subtab="clone-accounts">List account</div>
                            <div class="keshi-sub-tab " data-subtab="clone-status">Status</div>
                            <div class="keshi-sub-tab" data-subtab="clone-mine">Khoáng</div>
                        </div>
                        <div class="keshi-sub-tab-content">
                            <div class="keshi-tab-pane active" id="keshi-clone-accounts-pane">
                                <div class="keshi-form-group">
                                    <label for="keshiCloneId">ID:</label>
                                    <input type="text" id="keshiCloneId" placeholder="Nhập ID clone">
                                </div>
                                <button class="keshi-btn keshi-btn-primary" id="keshiAddClone">Thêm clone</button>

                                <div class="keshi-target-list" id="keshi-clone-list"></div>
                            </div>

                            <div class="keshi-tab-pane" id="keshi-clone-status-pane">
                                <div class="keshi-miner-list" id="keshi-clone-status"></div>
                            </div>
                            <div class="keshi-tab-pane" id="keshi-clone-mine-pane">
                                <div class="keshi-miner-list" id="keshi-clone-mine"></div>
                            </div>
                        </div>
                    </div>
                    <div class="keshi-tab-pane active" id="keshi-dig-pane">
                        <div class="keshi-sub-tabs">
                            <div class="keshi-sub-tab active" data-subtab="setting">Mục tiêu</div>
                            <div class="keshi-sub-tab" data-subtab="miner">Khoáng</div>
                        </div>

                        <div class="keshi-sub-tab-content">
                            <div class="keshi-tab-pane active" id="keshi-setting-pane">
                                <div class="keshi-form-group">
                                    <label for="keshiTargetId">ID:</label>
                                    <input type="text" id="keshiTargetId" placeholder="Nhập ID">
                                </div>
                                <div class="keshi-form-group">
                                    <label for="keshiTargetNickname">Biệt danh:</label>
                                    <input type="text" id="keshiTargetNickname" placeholder="Nhập biệt danh">
                                </div>
                                <div class="keshi-form-group">
                                    <label for="keshiTargetMode">Chế độ:</label>
                                    <select id="keshiTargetMode">
                                        <option value="UntilDead">Dí đến chết</option>
                                        <option value="Once">Dí 1 lần</option>
                                    </select>
                                </div>
                                <div class="keshi-form-group">
                                    <label for="keshiTargetLimit">Giới hạn dí:</label>
                                    <input type="number" id="keshiTargetLimit" placeholder="Số lượt tối đa trong ngày...(Mặc định k giới hạn) min="1" step="1"">
                                </div>
                                <button class="keshi-btn keshi-btn-primary" id="keshiAddTarget">Thêm mục tiêu</button>

                                <div class="keshi-target-list" id="keshiTargetList"></div>
                            </div>

                            <div class="keshi-tab-pane" id="keshi-miner-pane">
                                <div class="keshi-miner-list" id="keshiMinerList"></div>
                            </div>
                        </div>
                    </div>

                    <div class="keshi-tab-pane" id="keshi-stats-pane">
                        <div class="keshi-sub-tabs">
                            <div class="keshi-sub-tab active" data-subtab="today">Hôm nay</div>
                            <div class="keshi-sub-tab" data-subtab="all">Toàn bộ</div>
                        </div>

                        <div class="keshi-sub-tab-content">
                            <div class="keshi-tab-pane active" id="keshi-today-pane">
                                <div class="keshi-target-list" id="keshi-stat-today"></div>
                            </div>

                            <div class="keshi-tab-pane" id="keshi-all-pane">
                                <div class="keshi-miner-list" id="keshi-stat-all"></div>
                            </div>
                        </div>
                    </div>

                    <div class="keshi-tab-pane" id="keshi-settings-pane">
                        <div class="keshi-sub-tabs">
                            <div class="keshi-sub-tab active" data-subtab="mine">Khoáng</div>
                            <div class="keshi-sub-tab" data-subtab="activity">Hoạt động</div>
                        </div>

                        <div class="keshi-sub-tab-content">
                            <div class="keshi-tab-pane active" id="keshi-mine-pane">
                            </div>

                            <div class="keshi-tab-pane" id="keshi-acitivity-pane">
                            </div>
                        </div>
                    </div>
                </div>
            </div>

            <!-- Modal xác nhận thêm mục tiêu -->
            <div class="keshi-modal" id="keshiConfirmModal" style="display: none;">
                <div class="keshi-modal-content">
                    <div class="keshi-modal-header">Xác nhận thêm mục tiêu</div>
                    <div id="keshiCharacterInfo"><div class="keshi-loading">Đang tải thông tin...</div></div>
                    <div class="keshi-modal-actions">
                        <button class="keshi-btn keshi-btn-primary" id="keshiConfirmAdd">Thêm</button>
                        <button class="keshi-btn keshi-btn-danger" id="keshiCancelAdd">Hủy</button>
                    </div>
                </div>
           </div>
        `;

            this.setupEventListeners();
        }

        setupEventListeners() {
            const minerToggle = this.minerUI.querySelector('#keshiMinerToggle');
            const minerMenu = this.minerUI.querySelector('#keshiMinerMenu');

            // Toggle menu
            minerToggle.addEventListener('click', e => {
                e.stopPropagation();
                minerMenu.classList.toggle('active');
            });

            // Close menu if clicked outside
            document.addEventListener('click', e => {
                if (!this.minerUI.contains(e.target)) minerMenu.classList.remove('active');
            });

            // Tabs chính
            this.minerUI.querySelectorAll('.keshi-tab').forEach(tab => {
                tab.addEventListener('click', () => {
                    this.minerUI.querySelectorAll('.keshi-tab').forEach(t => t.classList.remove('active'));
                    tab.classList.add('active');

                    this.minerUI.querySelectorAll('.keshi-tab-pane').forEach(p => p.classList.remove('active'));
                    const tabId = tab.dataset.tab;
                    const tabPane = this.minerUI.querySelector(`#keshi-${tabId}-pane`);
                    tabPane.classList.add('active');

                    const firstSubTab = tabPane.querySelector('.keshi-sub-tab.active') || tabPane.querySelector('.keshi-sub-tab');
                    if (firstSubTab) firstSubTab.click();
                });
            });

            // Sub-tabs
            this.minerUI.querySelectorAll('.keshi-sub-tab').forEach(subTab => {
                subTab.addEventListener('click', () => {
                    // bỏ active khỏi tất cả subtab
                    this.minerUI.querySelectorAll('.keshi-sub-tab').forEach(t => t.classList.remove('active'));
                    subTab.classList.add('active');

                    // bỏ active khỏi tất cả pane trong cùng cha
                    const parentContent = subTab.closest('.keshi-tab-pane').querySelector('.keshi-sub-tab-content');
                    parentContent.querySelectorAll('.keshi-tab-pane').forEach(p => p.classList.remove('active'));

                    // active pane đúng theo data-subtab
                    const subtabId = subTab.dataset.subtab;
                    const targetPane = parentContent.querySelector(`#keshi-${subtabId}-pane`);
                    if (targetPane) targetPane.classList.add('active');
                });
            });
            // Sau khi setupEventListeners
            // Tìm tab đang active và trigger click
            const activeTab = this.minerUI.querySelector('.keshi-tab.active');
            if (activeTab) activeTab.click();

            // Với subtab cũng vậy
            const activeSubTab = this.minerUI.querySelector('.keshi-sub-tab.active');
            if (activeSubTab) activeSubTab.click();

            // Thêm mục tiêu
            this.minerUI.querySelector('#keshiAddTarget').addEventListener('click', () => this.handleAddTarget());

            this.minerUI.querySelector('#keshiAddClone').addEventListener('click', () => this.handleAddClone());
        }

        renderTargetList() {
            //console.log(this.targetManager.targets)
            const targetList = this.minerUI.querySelector('#keshiTargetList');
            targetList.innerHTML = '';

            if (!this.targetManager.targets.length) {
                targetList.innerHTML = '<p>Chưa có mục tiêu nào. Hãy thêm mục tiêu mới.</p>';
                return;
            }

            this.targetManager.targets.forEach(target => {
                const targetElement = document.createElement('div');
                targetElement.className = 'keshi-target-item';
                targetElement.innerHTML = `
                <div class="keshi-target-info">
                    <div><strong>ID:</strong> ${target.id}</div>
                    <div><strong>Tên:</strong> ${target.name}</div>
                    <div><strong>Biệt danh:</strong> ${target.nickname || 'N/A'}</div>
                    <div><strong>Chế độ:</strong> ${target.mode == "UntilDead" ? "Dí đến chết" : "Đấm 1 lần"}</div>
                    <div><strong>Trạng thái:</strong> ${target.processing ? "Đang dí" : "Đã dừng"}</div>
                </div>
                <div class="keshi-target-actions">
                    <button class="keshi-btn keshi-btn-danger" data-id="${target.id}">Xóa</button>
                </div>
            `;
                targetElement.querySelector('.keshi-btn-danger').addEventListener('click', () => {
                    if (confirm('Bạn có chắc chắn muốn xóa mục tiêu này?')) {
                        this.targetManager.removeTarget(target.id);
                        this.renderTargetList();
                    }
                });

                targetList.appendChild(targetElement);
            });
        }

        renderMiningList() {
            const minerList = this.minerUI.querySelector('#keshiMinerList');
            minerList.innerHTML = '';

            if(!this.targetManager.targets.length) {
                minerList.innerHTML = '<p>Chưa có mục tiêu nào.</p>';
                return;
            }
            if (!this.miningManager.targets.length) {
                minerList.innerHTML = '<p>Đang tải dữ liệu</p>';
                return;
            }

            this.miningManager.targets.forEach(target => {
                const minerItem = document.createElement('div');
                minerItem.className = 'keshi-miner-item';
                minerItem.dataset.targetId = target.id;

                minerItem.innerHTML = `
                <div class="keshi-miner-header">
                    <div style="display: flex; align-items: center;">
                        <img src="${target?.avatar}" style="width: 40px; height: 40px; border-radius: 50%; margin-right: 10px;" onerror="this.src='https://via.placeholder.com/40'">
                        <div>
                            <div><strong>${target?.name}</strong></div>
                            <div>ID: ${target.id}</div>
                        </div>
                    </div>
                    <span class="keshi-miner-status" data-status="idle">${target.processing ? "Đang tiến hành" : "Chưa bắt đầu"}</span>
                </div>
                <div class="keshi-miner-details">
                    <div><strong>Guild:</strong> ${target?.guild || 'N/A'}</div>
                    <div><strong>Biệt danh:</strong> ${target?.nickname || 'N/A'}</div>
                    <div><strong>Chế độ:</strong> ${target.mode}</div>
                    <div><strong>Lần cuối dí:</strong> <span class="keshi-last-mined">Chưa có</span></div>
                </div>
                <hr>
                <div class="">
                    <div class="keshi-detail-miner"><strong>Số lượt còn lại:</strong>${target?.energy?.current}</div>
                    <div class="keshi-detail-miner"><strong>Lần thêm lượt tiếp theo lúc:</strong>${new Date(target?.energy?.next_energy * 1000 ).toLocaleString("vi-VN", {timeZone: "Asia/Ho_Chi_Minh"})}</div>
                    <div class="keshi-detail-miner"><strong>Trạng thái khoáng:</strong> ${target?.miner ? '<span style="font-size:18px;">🟢Đang đào khoáng</span>' : '<span style="font-size:18px;">🔴Off</span>'}</div>
                    ${target?.miner ? `
                    <div class="keshi-detail-miner"><strong>Đang ngồi khoáng ở tầng:</strong> ${target?.miner?.area || 'N/A'}</div>
                    <div class="keshi-detail-miner"><strong>Rare:</strong> ${RARE[target?.miner?.rare]?.name}</div>
                    <div class="keshi-detail-miner"><strong>Thời gian:</strong> <span class="keshi-last-mined">Chưa có</span></div>
                    <div class="keshi-detail-miner"><strong>Mine id:</strong> ${target?.miner?.mine_id || 'N/A'}</div>
                    <div class="keshi-detail-miner"><strong>Dùng khiên:</strong> ${target?.miner?.isProtect ? "Có khiên" : "Không"}</div>
                    ` : ''}
                </div>
                <div class="keshi-mining-controls" style="margin-top: 10px;">
                    <button class="keshi-btn keshi-btn-${target.processing ? "danger" : "primary"} keshi-start-mining" data-target-color = {}  data-target-id="${target.id}">${target.processing ? "Dừng lại" : "Bắt đầu"}</button>
                </div>
                <div class="keshi-mining-results" style="margin-top: 10px; display: none;">
                    <div class="keshi-mining-stats">
                        <span class="keshi-stat-success">Thành công: 0</span>
                        <span class="keshi-stat-fail">Thất bại: 0</span>
                    </div>
                </div>
            `;

                minerList.appendChild(minerItem);
                const button = minerItem.querySelector(".keshi-start-mining");
               button.addEventListener("click", () => {
                   const targetId = button.dataset.targetId;
                   const newProcessingState = window.TargetManager.updateProcess(targetId);
                   button.textContent = newProcessingState ? "Dừng lại" : "Bắt đầu";
                   button.classList.remove('keshi-btn-danger', 'keshi-btn-primary');
                   button.classList.add(`keshi-btn-${newProcessingState ? "danger" : "primary"}`);

                   // Cập nhật cả trạng thái hiển thị
                   const statusSpan = minerItem.querySelector('.keshi-miner-status');
                   statusSpan.textContent = newProcessingState ? "Đang tiến hành" : "Chưa bắt đầu";
                   statusSpan.dataset.status = newProcessingState ? "processing" : "idle";
               });
            });
        }

        renderCloneList() {
            const cloneList = this.minerUI.querySelector('#keshi-clone-list');
            cloneList.innerHTML = '';
            //console.log("Render clone list:", this.accountManager.accounts)

            if (!this.accountManager.accounts.length) {
                cloneList.innerHTML = '<p>Chưa có clone nào. Hãy thêm clone mới.</p>';
                return;
            }

            this.accountManager.accounts.forEach(account => {
                const accountElement = document.createElement('div');
                accountElement.className = 'keshi-target-item';
                accountElement.innerHTML = `
                <div class="keshi-target-info">
                    <div><strong>ID:</strong> ${account.id}</div>
                    <div><strong>Tên:</strong> ${account.name}</div>
                    <div><strong>Tên:</strong> ${account.guild}</div>
                </div>
                <div class="keshi-target-actions">
                    <button class="keshi-btn keshi-btn-danger" data-id="${target.id}">Xóa</button>
                </div>
            `;
                accountElement.querySelector('.keshi-btn-danger').addEventListener('click', () => {
                    if (confirm('Bạn có chắc chắn muốn xóa mục tiêu này?')) {
                        this.accountManager.removeAccount(target.id);
                        this.renderCloneList();
                    }
                });

                cloneList.appendChild(accountElement);
            });
        }

        renderDetailCloneList() {
            const detailCloneList = this.minerUI.querySelector('#keshi-detail-clone-list');
            detailCloneList.innerHTML = '';
            const accounts = this.accountManager.accounts;
            if (!accounts || !accounts.length) {
                detailCloneList.innerHTML = '<div class="keshi-stat-item"><div><span>Chưa có dữ liệu</span></div></div>';
                return;
            }
            accounts.forEach(account => {
                const {info = {}, activity = {}} = account;
                const {id, name, level, guild, legendary} = info;
                const daily = activity?.daily || {};

            })
        }

        generateLogMessage(stat) {
            if (!stat) {
                return `
                    <div class="keshi-stat-item ">
                        <div><span>Chưa có dữ liệu</span></div>
                    </div>
                `;
            }
            let message = "";
            const time = getTime( new Date(stat?.time));
            const timeSpan = `<div class="time">${time}</div>`;
            // class mặc định
            let statusClass = "";

            switch (stat.action) {
                case 'attack':
                case 'isAttacked': {
                    statusClass = (stat.action === "attack") === (stat.detail.success) ? "success" : "fail"
                    const targetText = stat.detail.target ? `<span>${stat.detail.target.name} ID ${stat.detail.target.id}</span>` : "";
                    const detailText = stat.detail ? `<a class="detail" onclick="battle_id = ${stat.detail.battle_id};frame_load('battle');"> &lt;Chi tiết: <span>Chiến báo ${stat.detail.battle_id}</span>&gt;</a>` : '';

                    if (stat.action === 'attack') {
                        message = `Bạn đã <span style="color: ${COLOR_CODE[statusClass].color}"> ${statusClass === "success" ? "tiêu diệt" : "thất bại khi tấn công"}</span> ${targetText} trong ${stat.detail.map}.${detailText}`;
                    } else if (stat.action === "isAttacked") {
                        message = `Bạn đã <span style="color: ${COLOR_CODE[statusClass].color}"> ${statusClass === "success" ? "bị tiêu diệt" : "bị tấn công"}</span> bởi ${targetText} trong ${stat.detail.map}.${detailText}`;
                        statusClass = stat.detail.success ? "fail" : "success";
                    }
                    break;
                }
                case 'buy': {
                    const quantity = stat.detail?.quantity || 0;
                    const itemName = stat.detail?.item || 'vật phẩm';
                    const price = stat.detail?.price || 0;
                    message = `Bạn đã mua ${quantity} ${itemName} với giá ${price}lt.`;
                    statusClass = "register"; // ví dụ coi như giao dịch thành công
                    break;
                }
                case 'read': {
                    message = `Bạn đã ${ACTION[stat.action]} ${stat.detail}`;
                    statusClass = "register";
                    break;
                }
                default: {
                    message = `Bạn đã ${ACTION[stat.action]} ${stat.other || ''}`;
                    statusClass = "register";
                    break;
                }
            }
            //console.log(message)

            return `
        <div class="keshi-stat-item ${statusClass}">
            <div><span>${timeSpan}</span></div>
            <div class="flex">${message}</div>
        </div>
    `;
        }
        generateDayBlock(date, statArray) {
            const sortedStats = [...statArray].sort((a, b) => b.time - a.time); // sắp xếp mới → cũ
            return `
              <div class="keshi-stat-day" data-date="${date}">
                <h3>Nhật ký ngày ${date}</h3>
                ${statArray?.length ? sortedStats.map(stat => this.generateLogMessage(stat)).join("") : "Chưa có dữ liệu gì về ngày hôm nay"}
                <hr>
              </div>
            `;
        }
        parseDDMMYYYY(dateStr) {
            const [day, month, year] = dateStr.split("/").map(Number);
            return new Date(year, month - 1, day);
        }

        renderStatsList({ mode = "all" } = {}) {
            let container;
            if (mode === "all") {
                container = this.minerUI.querySelector('#keshi-stat-all');
            } else if (mode === "today") {
                container = this.minerUI.querySelector('#keshi-stat-today');
            } else {
                console.error("Sai mode:", mode);
                return;
            }
            //console.log("mode",mode)

            if (!container) {
                console.error("Không tìm thấy container để render:", mode);
                return;
            }

            container.innerHTML = '';

            const stats = (mode === "all") ? this.statManager.stats : this.statManager.getToday();
            /*if (!stats || Object.keys(stats).length === 0) {
                container.innerHTML = '<p>Chưa có thông tin nào.</p>';
                return;
            }*/

            let html = '';

           if (mode === "all") {
               // render tất cả ngày, mới → cũ
               html = Object.entries(stats)
                   .sort(([dateA], [dateB]) => this.parseDDMMYYYY(dateB) - this.parseDDMMYYYY(dateA))
                   .map(([date, statArray]) => this.generateDayBlock(date, statArray))
                   .join("");
           } else {
               // render chỉ hôm nay
               const todayKey = getTime(new Date()).split(" ")[1];
               html = this.generateDayBlock(todayKey, stats);
           }

            container.innerHTML = html;
        }

        updateStatsDisplay(stat) {
            if (!stat) return;
            const newItemHTML = this.generateLogMessage(stat);
            const todayKey = getTime(new Date(stat.time)).split(" ")[1];

            // --- Update tab "today" ---
            const todayContainer = this.minerUI.querySelector("#keshi-stat-today");
            if (todayContainer) {
                let todayBlock = todayContainer.querySelector(`.keshi-stat-day[data-date="${todayKey}"]`);
                if (!todayBlock) {
                    todayContainer.insertAdjacentHTML("afterbegin",
                                                      `<div class="keshi-stat-day" data-date="${todayKey}">
                    <h3>Nhật ký ngày ${todayKey}</h3>
                    ${newItemHTML}
                    <hr>
                </div>`
                                                     );
                } else {
                    const h3 = todayBlock.querySelector("h3");
                    h3.insertAdjacentHTML("afterend", newItemHTML);
                }
            }

            // --- Update tab "all" ---
            const allContainer = this.minerUI.querySelector("#keshi-stat-all");
            if (allContainer) {
                let dateBlock = allContainer.querySelector(`.keshi-stat-day[data-date="${todayKey}"]`);
                if (!dateBlock) {
                    allContainer.insertAdjacentHTML("afterbegin",
                                                    `<div class="keshi-stat-day" data-date="${todayKey}">
                    <h3>Nhật ký ngày ${todayKey}</h3>
                    ${newItemHTML}
                    <hr>
                </div>`
                                                   );
                } else {
                    const h3 = dateBlock.querySelector("h3");
                    h3.insertAdjacentHTML("afterend", newItemHTML);
                }
            }
        }

        handleAddTarget() {
            const targetId = this.minerUI.querySelector('#keshiTargetId').value;
            const targetNickname = this.minerUI.querySelector('#keshiTargetNickname').value;
            const targetMode = this.minerUI.querySelector('#keshiTargetMode').value;
            const targetLimit = parseInt(this.minerUI.querySelector('#keshiTargetLimit').value) || "infinity";

            if (!targetId) return alert('Vui lòng nhập ít nhất ID!');

            if (this.targetManager.targets.some(t => t.id === targetId)) {
                return alert('ID này đã tồn tại trong danh sách!');
            }

            const confirmModal = this.minerUI.querySelector('#keshiConfirmModal');
            confirmModal.style.display = 'flex';

            fetch(`/api/get_data_by_id?table=game_character&data=info&id=${targetId}`)
                .then(res => res.json())
                .then(data => {
                const info = JSON.parse(data.info);
                const name = info.name;
                const guild = info.guild ? info.guild.name : 'Không có guild';
                const avatar = `/assets/tmp/avatar/${info.avatar}`;

                const characterInfo = this.minerUI.querySelector('#keshiCharacterInfo');
                characterInfo.innerHTML = `
                    <div class="keshi-character-info">
                        <img src="${avatar}" class="keshi-character-avatar">
                        <div>
                            <div>${info?.id}</div>
                            <div>${name}</div>
                            <div>Guild: ${guild}</div>
                        </div>
                    </div>
                    <div class="keshi-form-group">
                        <label>Biệt danh:</label>
                        <input type="text" id="keshiConfirmNickname" value="${targetNickname || ''}">
                    </div>
                    <div class="keshi-form-group">
                        <label>Chế độ:</label>
                        <select id="keshiConfirmMode">
                            <option value="UntilDead" ${targetMode === 'UntilDead' ? 'selected' : ''}>Dí đến chết</option>
                            <option value="Once" ${targetMode === 'Once' ? 'selected' : ''}>Dí 1 lần</option>
                        </select>
                    </div>
                    <div class="keshi-form-group">
                        <label>Giới hạn dí mỗi ngày:</label>
                        <input type="text" id="keshiConfirmNickname" value="${targetLimit || ''}">
                    </div>
                `;

                // Xác nhận thêm
                this.minerUI.querySelector('#keshiConfirmAdd').onclick = async () => {
                    const confirmedNickname = this.minerUI.querySelector('#keshiConfirmNickname').value;
                    const confirmedMode = this.minerUI.querySelector('#keshiConfirmMode').value;

                    const newTarget = { id: targetId, name, nickname: confirmedNickname, mode: confirmedMode, guild, avatar };
                    this.targetManager.addTarget(newTarget);
                    this.renderTargetList();
                    confirmModal.style.display = 'none';
                    this.minerUI.querySelector('#keshiTargetId').value = '';
                    this.minerUI.querySelector('#keshiTargetNickname').value = '';
                    if (window.autoMiner) {
                        console.log("⚡ Reload AutoMiner after adding target...");
                        await window.autoMiner.init();
                    }
                };

                this.minerUI.querySelector('#keshiCancelAdd').onclick = () => confirmModal.style.display = 'none';
            })
                .catch(err => console.error('Lỗi khi lấy thông tin nhân vật:', err));
        }

        handleAddClone() {
            const cloneId = this.minerUI.querySelector('#keshiCloneId').value;

            if (!cloneId) return alert('Vui lòng nhập ít nhất ID!');

            if (this.accountManager.accounts.some(t => t.id === cloneId)) {
                return alert('ID này đã tồn tại trong danh sách!');
            }
            const confirmModal = this.minerUI.querySelector('#keshiConfirmModal');
            confirmModal.style.display = 'flex';

            fetch(`/api/get_data_by_id?table=game_character&data=info&id=${cloneId}`)
                .then(res => res.json())
                .then(data => {
                const info = JSON.parse(data.info);
                const name = info.name;
                const guild = info.guild ? info.guild.name : 'Không có guild';
                const avatar = `/assets/tmp/avatar/${info.avatar}`;
                                const characterInfo = this.minerUI.querySelector('#keshiCharacterInfo');
                characterInfo.innerHTML = `
                    <div class="keshi-character-info">
                        <img src="${avatar}" class="keshi-character-avatar">
                        <div>
                            <div>${info?.id}</div>
                            <div>${name}</div>
                            <div>Guild: ${guild}</div>
                        </div>
                    </div>
                `;

                this.minerUI.querySelector('#keshiConfirmAdd').onclick = async () => {
                    const newTarget = { info: {id: cloneId, name, guild, avatar }};
                    this.accountManager.addAccount(newTarget);
                    this.renderCloneList();
                    confirmModal.style.display = 'none';
                    this.minerUI.querySelector('#keshi-clone-id').value = '';
                    if (window.autoMiner) {
                        console.log("⚡ Reload AutoMiner after adding target...");
                        await window.autoMiner.init();
                    }
                };

                this.minerUI.querySelector('#keshiCancelAdd').onclick = () => confirmModal.style.display = 'none';
            })
                .catch(err => console.error('Lỗi khi lấy thông tin nhân vật:', err));
        }
    }

    class AutoMiner {
        constructor(targetManager, miningManager, statsManager,accountMangaer,urlConfig, diffTimeServer = 0) {
            this.TargetManager = targetManager;
            this.MiningManager = miningManager;
            this.StatsManager = statsManager;
            this.URL = urlConfig;
            this.diffTimeServer = diffTimeServer;
            this.AccountManager= accountMangaer;

            // Tự động khởi tạo khi tạo instance
            console.log("[DEBUG] StatsManager:", this.StatsManager);

            this.init();
            setInterval(() => {
                this.init();
            },5 * 60 * 1000);
        }

        async processMiner(list_target, miner, area, index) {
            try {
                if (!list_target.includes(parseInt(miner.target, 10))) return null;

                const data = JSON.parse(miner.data);
                const reward = data.miner?.reward;
                const isProtect = !!data.miner?.protect;

                if (!reward || typeof reward !== 'object' || isProtect) return null;

                return {
                    area,
                    rare: data.rare,
                    stt: index + 1,
                    mine_id: parseInt(miner.id_score, 10),
                    character_id: parseInt(miner.target, 10),
                    author: data.miner?.info?.name,
                    isProtect
                };
            } catch (e) {
                console.error(`Error processing miner: ${e}`);
                return null;
            }
        }

        async processArea(targetIds, area) {
            try {
                const url = this.URL.HMK_AREA(area);
                const response = await fetch(url);
                const miners = await response.json();

                const minersPromises = miners.map((miner, index) => this.processMiner(targetIds, miner, area, index));
                const areaResults = await Promise.all(minersPromises);
                return areaResults.filter(item => item !== null);
            } catch (e) {
                console.error(`Error processing area ${area}: ${e}`);
                GM_notification(`Lỗi khi xử lý tầng ${area}: ${e.message}`, 'Lỗi');
                return [];
            }
        }

        async getEnergy(id) {
            try {
                const url = this.URL.ENERGY(id);
                const response = await fetch(url);
                if (response.status === 200) {
                    const data = await response.json();
                    return {
                        current: data.current,
                        next_energy: data.time + this.diffTimeServer
                    };
                }
            } catch (e) {
                console.error('Lỗi khi check lượt đánh:', e);
                window.location.reload();
            }
        }

        async getHmkArea(targetIds) {
            const areas = Array.from({ length: 11 }, (_, i) => i + 1);
            const areaPromises = areas.map(area => this.processArea(targetIds, area));
            const allResults = await Promise.all(areaPromises);
            return allResults.flatMap(arr => arr);
        }

        async processBattle (mine_id) {
            try {
                const response = await fetch(
                    `/assets/ajax/character_activity.php`,
                    {
                        method: 'POST',
                        headers: {
                            "Content-Type": "application/x-www-form-urlencoded"
                        },
                        body: `action=battle_mine_challenge&mine_id=${mine_id}&target=private`
                    }
                );
                //attackEndTime = Date.now();

                const responseText = await response.text();
                if (!responseText || responseText.trim() == "" ||responseText.includes("<!--empty-->")) {
                    window.location.reload()
                }

                const parser = new DOMParser();
                const doc = parser.parseFromString(responseText, "text/html");
                const scripts = doc.getElementsByTagName('script');
                let isWeak = false;
                let battle_id = null;
                let popupData = {};
                let popupDataRaw = {};
                let isSuccess = false;// trạng thái request
                let errorMessage = '';
                let battleLoaded = false;
                let status = true; //thành công hay thất bại

                for (const script of scripts) {
                    const scriptContent = script.textContent;
                    const battleIdMatch = scriptContent.match(/battle_id\s*=\s*'([^']+)'/);
                    if (battleIdMatch) {
                        battle_id = battleIdMatch[1];
                        console.log(`[DEBUG] Found battle_id: ${battle_id}`);
                    }

                    if (scriptContent.includes("alertify.success")) {
                        isSuccess = true;
                        console.log("Tấn công thành công");
                    } else if (scriptContent.includes("alertify.error")) {
                        isSuccess = false;
                        status = false;
                        const errorMatch = scriptContent.match(/alertify\.error\('([^']+)'\)/);
                        if (errorMatch) {
                            errorMessage = errorMatch[1];
                            console.log('[DEBUG] Lỗi khi khiêu chiến:', errorMessage);
                        }
                    }

                    const popupMatch = scriptContent.match(/popup_data\s*=\s*({[\s\S]*?})\s*;/);
                    if (popupMatch) {
                        try {
                            const rawData = JSON.parse(popupMatch[1]);
                            console.log('[DEBUG] Parsed popup_data:', rawData);
                            popupData = Object.fromEntries(
                                Object.entries(rawData)
                                .filter(([key]) => key !== 'gold' && key !== 'mine_ore')
                                .map(([key, value]) => {
                                    if (value && typeof value === 'object' && 'amount' in value) {
                                        return [key, value.amount];
                                    }
                                    return [key, value];
                                })
                            );
                            popupDataRaw = Object.fromEntries(
                                Object.entries(rawData)
                                .filter(([key]) => key)
                                .map(([key, value]) => {
                                    if (value && typeof value === 'object' && 'amount' in value) {
                                        return [key, value.amount];
                                    }
                                    return [key, value];
                                })
                            );
                            console.log("[processBattle] done parse popup_data");
                        } catch (e) {
                            console.error('[DEBUG] Lỗi parse popup_data:', e);
                        }
                    }
                }

                return {
                    success: isSuccess,
                    popupData: popupData,
                    popupDataRaw: popupDataRaw,
                    error: errorMessage,
                    status: status,
                    rawResponse: responseText,
                    battle_id: battle_id ? battle_id : null
                };

            } catch (error) {
                console.error('[DEBUG] Lỗi processBattle:', {
                    error: error,
                    stack: error.stack
                });
                return {
                    success: false,
                    error: error?.message || error,
                    //rawResponse: responseText
                };
            }
        };

        async autoAttack () {
            try {
                if (!this.MiningManager?.targets?.length) {
                    console.warn("[autoAttack] Không có targets để xử lý");
                    return;
                }
                //tạo khóa bảo vẹ trong trường hợp k mặc đồ  = cách check set hoặc

                for (const target of this.MiningManager.targets) {
                    if (!target.processing || !target.miner) continue;
                    const miner = target.miner;

                    const doAttack = async () => {
                        const energy = await this.getEnergy(window?.my_character);
                        if (energy.current <= 0) {
                            const wait_time =energy.next_energy  * 1000 - Date.now();
                            console.log(`[autoAttack] Hết lượt đánh, chờ thêm lượt sau ${Math.ceil(wait_time / 1000)} giây...`);
                            await new Promise(res => setTimeout(res, wait_time + 2000));
                            return doAttack();
                        }
                        console.log(`[autoAttack] Tấn công target ${target.id} - mine_id: ${miner.mine_id}`);
                        const response = await this.processBattle(miner.mine_id);

                        const stat = {
                            time: Date.now(),
                            action: "attack",
                            detail: {
                                target: {
                                    id: target.id,
                                    name: target.name,
                                    guild: target?.guild || ""
                                },
                                success: response?.status,
                                map: "Hồng mao khoáng",
                                battle_id: response?.battle_id || null,
                                error: response?.error || null
                            }
                        };

                        this.StatsManager.add(stat);
                        // Nếu thất bại và mode != Once thì lặp lại
                        if (response?.status === false && target.mode !== "Once") {
                            console.log(`[autoAttack] Attack thất bại, thử lại target ${target.id}...`)
                            await new Promise(res => setTimeout(res, 2000))
                            return doAttack()
                        }
                        return response;
                    };



                    if(miner?.isProtect === true ||(miner?.isProtect && miner.isProtect.time)) {
                        const delay = miner.isProtect.time || 5 * 60 * 1000;
                        setTimeout(async () => {
                            if(!target.processing || !target.miner) return;
                            if (!target.miner.isProtect) {
                                await doAttack()
                            } else {
                                console.log(`[autoAttack] Target ${target.id} vẫn còn bảo vệ, bỏ qua.`)
                            }
                        }, delay)
                    } else {
                        await doAttack()
                    }
                }
            } catch (e){
                console.error("[autoAttack] Lỗi:", e);
            }
        }
        async getOther(id) {
            const resposne = await fetch(this.URL.OTHER(id))
            if (resposne.status === 200) {
                const data = await resposne.jon()
                const info = JSON.parse(data?.info)
                const other = JSON.parse(data?.other)
                return {
                    info: {
                        name: info.name,
                        avatar: info.avatar,
                        id: info.id,
                        guild: info.guild.name
                    },
                    other: {
                        energy: other.energy,
                        word: other.word,
                        legendary: other.legendary,
                        ancient: other.ancient,
                        time: other.time,
                        treasure_find: other.treasure_find,
                        guild_quest: other.guild_quest,
                        donate: other.donate,
                        guild_transpot: other.guild_transpot,
                        word_daily_event: other.word_daily_event,
                        training: other.training
                    }
                }
            }
            return null
        }

        async processAccountList() {
            const accounts = this.AccountManager.accounts;
            if (!accounts || !accounts.length) {
                console.warn("[processAccountList] Không có tài khoản để xử lý");
                return;
            }

            const accountPromises = accounts.map(async (account) => {
                const characterId = account.id;
                const characterData = await this.getOther(characterId);
                account.activity.daily = {
                    dungeon: {
                        current: parseInt(characterData?.other?.energy?.current),
                        buy: parseInt(characterData?.other?.energy?.buy),
                        turn: 30 - parseInt(characterData?.other?.energy?.remain) + parseInt(characterData?.other?.energy?.buy) || 0 - parseInt(characterData?.other?.energy?.current) || 0,
                        max: parseInt(account?.activity?.daily?.dungeon?.max) || 40
                    },
                    word: {
                        event: {
                            current: parseInt(characterData?.other?.word_daily_event?.day) == new Date().getDate() ? parseInt(characterData?.other?.word_daily_event?.current) : 0,
                        },
                        total_sign: parseInt(characterData?.other?.day) == new Date().getDate() ? parseInt(characterData?.other?.word?.num) : 0,
                    },
                    guild_transport: parseInt(characterData?.other?.guild_transpot?.day) === new Date().getDate(),
                    treasure_find: {
                        current: parseInt(characterData?.other?.treasure_find?.day) === new Date().getDate() ? parseInt(characterData?.other?.treasure_find?.num) : 0,
                        max: account.activity.daily.treasure_find.max ?? 3
                    }
                };
            });
            await Promise.all(accountPromises);
        }

        async init() {
            try {
                console.log("Init data")
                this.TargetManager.loadTargets();
                console.log(this.StatsManager)
                // Xóa dữ liệu cũ
                this.MiningManager.targets = [];
                console.log("mining::::", this.MiningManager.targets)

                const targetIds = this.TargetManager.targets.map(target => parseInt(target.id, 10));
                const hmkArea = await this.getHmkArea(targetIds);

                const minersByCharacterId = {};
                hmkArea.forEach(miner => {
                    minersByCharacterId[miner.character_id] = miner;
                });
                //console.log(hmkArea)

                // Dùng map để tạo mảng mới rồi gán thẳng
                const updatedTargets = await Promise.all(this.TargetManager.targets.map(async target => {
                    const targetId = parseInt(target.id, 10);

                    // Lấy thông tin energy
                    const energy = await this.getEnergy(targetId);

                    // Kiểm tra khoáng
                    const minerInfo = minersByCharacterId[targetId] || false;

                    return {
                        ...target,
                        energy: {
                            current: energy.current,
                            next_energy: energy.next_energy
                        },
                        miner: minerInfo,
                        lastUpdated: Date.now()
                    };
                }));

                this.MiningManager.targets = updatedTargets;
                console.log("mining",this.MiningManager.targets)
                await this.autoAttack()
            } catch (e) {
                console.error('Lỗi AutoMiner init:', e);
            }
        }
    }

    window.addEventListener('load', async () => {
        try {
            const { player_id, token_character, token_user } = await waitForGameKeys();
            window.my_character = player_id;
            window.token_character = token_character;
            window.token_user = token_user;
            const minerUI = new MinerUI();
            window.autoMiner = new AutoMiner(minerUI.targetManager, minerUI.miningManager, minerUI.statManager, minerUI.accountManager,URL, diffTimeServer);
            await window.autoMiner.init();
        } catch (error) {
            console.error('Lỗi khi khởi động script:', error);
        }
    });
})();