async function getSouls() {
    const mod = await System.import("chunks:///_virtual/FateDataCache.ts");
    const FateDataCache = mod.default;

    const fateCache = IS(FateDataCache);
    if (!fateCache) throw new Error("FateDataCache not found");

    const fateList = fateCache.GetFateList();
    if (!fateList) throw new Error("No fate data");

    const simplified = Object.values(fateList).map(f => ({
        name: f.cfg?.name ?? "Unknown",
        level: f.lv,
        id: f.id
    }));
    return simplified;
}

const soulEssense = [
    { level: 0, next: 0, total: 0 },
    { level: 1, next: 500, total: 0 },
    { level: 2, next: 600, total: 500 },
    { level: 3, next: 700, total: 1100 },
    { level: 4, next: 800, total: 1800 },
    { level: 5, next: 900, total: 2600 },
    { level: 6, next: 1000, total: 3500 },
    { level: 7, next: 1100, total: 4500 },
    { level: 8, next: 1200, total: 5600 },
    { level: 9, next: 1300, total: 6800 },
    { level: 10, next: 1400, total: 8100 },
    { level: 11, next: 1500, total: 9500 },
    { level: 12, next: 1600, total: 11000 },
    { level: 13, next: 1700, total: 12600 },
    { level: 14, next: 1800, total: 14300 },
    { level: 15, next: 1900, total: 16100 },
    { level: 16, next: 2000, total: 18000 },
    { level: 17, next: 2100, total: 20000 },
    { level: 18, next: 2200, total: 22100 },
    { level: 19, next: 2300, total: 24300 },
    { level: 20, next: 2400, total: 26600 },
    { level: 21, next: 2600, total: 29000 },
    { level: 22, next: 2800, total: 31600 },
    { level: 23, next: 3000, total: 34400 },
    { level: 24, next: 3200, total: 37400 },
    { level: 25, next: 3400, total: 40600 },
    { level: 26, next: 3600, total: 44000 },
    { level: 27, next: 3800, total: 47600 },
    { level: 28, next: 4000, total: 51400 },
    { level: 29, next: 4200, total: 55400 },
    { level: 30, next: 4400, total: 59600 },
    { level: 31, next: 4600, total: 64000 },
    { level: 32, next: 4800, total: 68600 },
    { level: 33, next: 5000, total: 73400 },
    { level: 34, next: 5200, total: 78400 },
    { level: 35, next: 5400, total: 83600 },
    { level: 36, next: 5600, total: 89000 },
    { level: 37, next: 5800, total: 94600 },
    { level: 38, next: 6000, total: 100400 },
    { level: 39, next: 6200, total: 106400 },
    { level: 40, next: 6400, total: 112600 },
    { level: 41, next: 6800, total: 119000 },
    { level: 42, next: 7200, total: 125800 },
    { level: 43, next: 7600, total: 133000 },
    { level: 44, next: 8000, total: 140600 },
    { level: 45, next: 8400, total: 148600 },
    { level: 46, next: 8800, total: 157000 },
    { level: 47, next: 9200, total: 165800 },
    { level: 48, next: 9600, total: 175000 },
    { level: 49, next: 10000, total: 184600 },
    { level: 50, next: 10400, total: 194600 },
    { level: 51, next: 10800, total: 205000 },
    { level: 52, next: 11200, total: 215800 },
    { level: 53, next: 11600, total: 227000 },
    { level: 54, next: 12000, total: 238600 },
    { level: 55, next: 12400, total: 250600 },
    { level: 56, next: 12800, total: 263000 },
    { level: 57, next: 13200, total: 275800 },
    { level: 58, next: 13600, total: 289000 },
    { level: 59, next: 14000, total: 302600 },
    { level: 60, next: 14400, total: 316600 },
    { level: 61, next: 15000, total: 331000 },
    { level: 62, next: 15600, total: 346000 },
    { level: 63, next: 16200, total: 361600 },
    { level: 64, next: 16800, total: 377800 },
    { level: 65, next: 17400, total: 394600 },
    { level: 66, next: 18000, total: 412000 },
    { level: 67, next: 18600, total: 430000 },
    { level: 68, next: 19200, total: 448600 },
    { level: 69, next: 19800, total: 467800 },
    { level: 70, next: 20400, total: 487600 },
    { level: 71, next: 21000, total: 508000 },
    { level: 72, next: 21600, total: 529000 },
    { level: 73, next: 22200, total: 550600 },
    { level: 74, next: 22800, total: 572800 },
    { level: 75, next: 23400, total: 595600 },
    { level: 76, next: 24000, total: 619000 },
    { level: 77, next: 24600, total: 643000 },
    { level: 78, next: 25200, total: 667600 },
    { level: 79, next: 25800, total: 692800 },
    { level: 80, next: 26400, total: 718600 },
    { level: 81, next: 27200, total: 745000 },
    { level: 82, next: 28000, total: 772200 },
    { level: 83, next: 28800, total: 800200 },
    { level: 84, next: 29600, total: 829000 },
    { level: 85, next: 30400, total: 858600 },
    { level: 86, next: 31200, total: 889000 },
    { level: 87, next: 32000, total: 920200 },
    { level: 88, next: 32800, total: 952200 },
    { level: 89, next: 33600, total: 985000 },
    { level: 90, next: 34400, total: 1018600 },
    { level: 91, next: 35200, total: 1053000 },
    { level: 92, next: 36000, total: 1088200 },
    { level: 93, next: 36800, total: 1124200 },
    { level: 94, next: 37600, total: 1161000 },
    { level: 95, next: 38400, total: 1198600 },
    { level: 96, next: 39200, total: 1237000 },
    { level: 97, next: 40000, total: 1276200 },
    { level: 98, next: 40800, total: 1316200 },
    { level: 99, next: 42000, total: 1357000 },
    { level: 100, next: 0, total: 1399000 }
]

function logSoulLevelComparison(soulName, desiredLevel, currentLevel, soulID) {
    const matches = desiredLevel === currentLevel;
    const color = matches ? '#4CAF50' : '#F44336';
    const status = matches ? '✓' : '✗';
    const requiresReset = desiredLevel < currentLevel;
    const message = `Desired ${soulName} Level: ${desiredLevel} | Current Level: ${currentLevel} ${status} ${requiresReset ? 'Requires Reset' : ''}`;
    console.log(`%c${message}`, `color: ${color}; font-weight: bold;`);
    if (requiresReset) {
        resetSoul(soulID);
        return Promise.resolve();
    }
    if (!requiresReset && !matches) {
        console.log("Raising soul: " + soulName + " (" + soulID + ") to level " + desiredLevel);
        return raiseSoul(soulID, desiredLevel, currentLevel).then(() => {
            console.log("Soul raise completed");
        }).catch((error) => {
            console.error("Error raising soul: " + error);
            throw error;
        });
    }
    return Promise.resolve();
}

function resetSoul(soulID) {
    console.log("Resetting soul: " + "soulName " + " (" + soulID + ")");
    window.sendFateReset(soulID);
}

async function raiseSoul(soulID, desiredLevel, currentLevel) {
    const levelDifference = desiredLevel - currentLevel;
    if (levelDifference <= 0) return;

    for (let i = 0; i < levelDifference; i++) {
        window.sendFateRaise(soulID);
        await new Promise(r => setTimeout(r, 100));
    }
}

function calcGemCost(currentSouls, activeLoadout) {
    let totalCost = 0;
    const soulNames = ["Blade Duo", "Bloodstained Blade", "Excellent Companion", "Eye of the Abyss", "Forgiving Horns", "Guardian Star", "Immortal Spirit", "Wildfire Piercer"];
    
    for (let i = 0; i < 8; i++) {
        const soulName = soulNames[i];
        const currentSoul = currentSouls.find(s => s.name === soulName);
        if (!currentSoul) continue;
        
        const currentLevel = currentSoul.level;
        const desiredLevel = activeLoadout.soul_levels[i];
        
        if (desiredLevel < currentLevel) {
            totalCost += 100;
        } else if (desiredLevel > currentLevel) {
            const levelDiff = desiredLevel - currentLevel;
            for (let level = currentLevel + 1; level <= desiredLevel; level++) {
                totalCost += level * 10;
            }
        }
    }
    
    return totalCost;
}

function showGemCostModal(gemCost) {
    return new Promise((resolve) => {
        const overlay = document.createElement('div');
        overlay.style.cssText = 'position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.7); z-index: 999999; display: flex; align-items: center; justify-content: center;';
        
        const modal = document.createElement('div');
        modal.style.cssText = 'background-color: #3e3f61; padding: 24px; border-radius: 12px; border: 2px solid black; text-align: center; min-width: 300px; max-width: 500px;';
        
        const title = document.createElement('div');
        title.textContent = 'Gem Cost Confirmation';
        title.style.cssText = 'font-size: 1.5em; font-weight: bold; color: white; margin-bottom: 16px; text-shadow: 1px 1px 2px black;';
        
        const costText = document.createElement('div');
        costText.textContent = `This will cost ${gemCost} gems`;
        costText.style.cssText = 'font-size: 1.2em; color: #ffd700; margin-bottom: 24px; font-weight: bold; text-shadow: 1px 1px 2px black;';
        
        const buttonContainer = document.createElement('div');
        buttonContainer.style.cssText = 'display: flex; gap: 12px; justify-content: center;';
        
        const continueBtn = document.createElement('button');
        continueBtn.textContent = 'Continue';
        continueBtn.style.cssText = 'background-color: #0ad36b; color: black; padding: 10px 20px; border-radius: 6px; border: 1.5px solid black; cursor: pointer; font-weight: bold; font-size: 1em;';
        continueBtn.onmouseover = () => continueBtn.style.backgroundColor = '#0fbd63';
        continueBtn.onmouseout = () => continueBtn.style.backgroundColor = '#0ad36b';
        continueBtn.onclick = () => {
            document.body.removeChild(overlay);
            resolve(true);
        };
        
        const cancelBtn = document.createElement('button');
        cancelBtn.textContent = 'Cancel';
        cancelBtn.style.cssText = 'background-color: #e44c4c; color: black; padding: 10px 20px; border-radius: 6px; border: 1.5px solid black; cursor: pointer; font-weight: bold; font-size: 1em;';
        cancelBtn.onmouseover = () => cancelBtn.style.backgroundColor = '#dd4343';
        cancelBtn.onmouseout = () => cancelBtn.style.backgroundColor = '#e44c4c';
        cancelBtn.onclick = () => {
            document.body.removeChild(overlay);
            resolve(false);
        };
        
        buttonContainer.appendChild(continueBtn);
        buttonContainer.appendChild(cancelBtn);
        
        modal.appendChild(title);
        modal.appendChild(costText);
        modal.appendChild(buttonContainer);
        overlay.appendChild(modal);
        
        document.body.appendChild(overlay);
    });
}

function showLoadoutNotification(success) {
    const notification = document.createElement('div');
    notification.style.cssText = 'position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: ' + (success ? '#0ad36b' : '#e44c4c') + '; padding: 24px 48px; border-radius: 12px; border: 2px solid black; text-align: center; z-index: 1000000; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5);';
    
    const text = document.createElement('div');
    text.textContent = success ? 'Loadout Complete' : 'Loadout Failed';
    text.style.cssText = 'font-size: 1.8em; font-weight: bold; color: black; text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.5);';
    
    notification.appendChild(text);
    document.body.appendChild(notification);
    
    setTimeout(() => {
        if (notification.parentNode) {
            notification.parentNode.removeChild(notification);
        }
    }, 500);
}

async function logLoadout() {
    try {
        (function () {
            const manager = window.netManager || window.fnNet || window.cManager;
            if (!manager || typeof manager.send !== "function") {
                console.warn("Net manager not found.");
                return;
            }
        
            window.sendFateReset = function (ID) {
                manager.send("fate.fate_reset_c2s", { fate_id: ID });
            };

            window.sendFateRaise = function (ID) {
                manager.send("fate.fate_level_up_c2s", { id: ID });
            };
        })();
        
        if (!window.__activeLoadoutData) {
            console.error('No active loadout data found. Make sure the loadout data is passed when injecting the script.');
            return;
        }
        
        const activeLoadout = window.__activeLoadoutData;
        const showGemCost = window.__showGemCost !== false;

        uiMgr.openView("FateInfoView");
        uiMgr.close("FateInfoView");
        
        const currentSouls = await getSouls();

        const Blade_Duo_ID = currentSouls.find(s => s.name === "Blade Duo").id;
        const Bloodstained_Blade_ID = currentSouls.find(s => s.name === "Bloodstained Blade").id;
        const Excellent_Companion_ID = currentSouls.find(s => s.name === "Excellent Companion").id;
        const Eye_of_the_Abyss_ID = currentSouls.find(s => s.name === "Eye of the Abyss").id;
        const Forgiving_Horns_ID = currentSouls.find(s => s.name === "Forgiving Horns").id;
        const Guardian_Star_ID = currentSouls.find(s => s.name === "Guardian Star").id;
        const Immortal_Spirit_ID = currentSouls.find(s => s.name === "Immortal Spirit").id;
        const Wildfire_Piercer_ID = currentSouls.find(s => s.name === "Wildfire Piercer").id;

        const Blade_Duo_Current = currentSouls.find(s => s.name === "Blade Duo").level;
        const Bloodstained_Blade_Current = currentSouls.find(s => s.name === "Bloodstained Blade").level;
        const Excellent_Companion_Current = currentSouls.find(s => s.name === "Excellent Companion").level;
        const Eye_of_the_Abyss_Current = currentSouls.find(s => s.name === "Eye of the Abyss").level;
        const Forgiving_Horns_Current = currentSouls.find(s => s.name === "Forgiving Horns").level;
        const Guardian_Star_Current = currentSouls.find(s => s.name === "Guardian Star").level;
        const Immortal_Spirit_Current = currentSouls.find(s => s.name === "Immortal Spirit").level;
        const Wildfire_Piercer_Current = currentSouls.find(s => s.name === "Wildfire Piercer").level;
        
        const Blade_Duo = activeLoadout.soul_levels[0];
        const Bloodstained_Blade = activeLoadout.soul_levels[1];
        const Excellent_Companion = activeLoadout.soul_levels[2];
        const Eye_of_the_Abyss = activeLoadout.soul_levels[3];
        const Forgiving_Horns = activeLoadout.soul_levels[4];
        const Guardian_Star = activeLoadout.soul_levels[5];
        const Immortal_Spirit = activeLoadout.soul_levels[6];
        const Wildfire_Piercer = activeLoadout.soul_levels[7];

        const currentSoulLevels = [Blade_Duo_Current, Bloodstained_Blade_Current, Excellent_Companion_Current, Eye_of_the_Abyss_Current, Forgiving_Horns_Current, Guardian_Star_Current, Immortal_Spirit_Current, Wildfire_Piercer_Current];
        const desiredSoulLevels = [Blade_Duo, Bloodstained_Blade, Excellent_Companion, Eye_of_the_Abyss, Forgiving_Horns, Guardian_Star, Immortal_Spirit, Wildfire_Piercer];

        const hasEssense = await calcEssense(currentSoulLevels, desiredSoulLevels);

        if (hasEssense) {
            if (showGemCost) {
                const gemCost = calcGemCost(currentSoulLevels, desiredSoulLevels);
                const shouldContinue = await showGemCostModal(gemCost);
                if (!shouldContinue) {
                    console.log("Loadout loading cancelled by user");
                    return;
                }
            }

            console.clear();
            
            const soulPromises = [
                logSoulLevelComparison("Blade Duo", Blade_Duo, Blade_Duo_Current, Blade_Duo_ID),
                logSoulLevelComparison("Bloodstained Blade", Bloodstained_Blade, Bloodstained_Blade_Current, Bloodstained_Blade_ID),
                logSoulLevelComparison("Excellent Companion", Excellent_Companion, Excellent_Companion_Current, Excellent_Companion_ID),
                logSoulLevelComparison("Eye of the Abyss", Eye_of_the_Abyss, Eye_of_the_Abyss_Current, Eye_of_the_Abyss_ID),
                logSoulLevelComparison("Forgiving Horns", Forgiving_Horns, Forgiving_Horns_Current, Forgiving_Horns_ID),
                logSoulLevelComparison("Guardian Star", Guardian_Star, Guardian_Star_Current, Guardian_Star_ID),
                logSoulLevelComparison("Immortal Spirit", Immortal_Spirit, Immortal_Spirit_Current, Immortal_Spirit_ID),
                logSoulLevelComparison("Wildfire Piercer", Wildfire_Piercer, Wildfire_Piercer_Current, Wildfire_Piercer_ID)
            ];
            
            Promise.all(soulPromises).then(() => {
                showLoadoutNotification(true);
            }).catch((error) => {
                console.error('Error completing loadout:', error);
                showLoadoutNotification(false);
            });

        }
        else {
            console.log("Not enough essense to load loadout");
            showLoadoutNotification(false);
        }
    } catch (error) {
        console.error('Error getting loadout:', error);
        showLoadoutNotification(false);
    }
}

async function calcEssense(currentSoulLevels, desiredSoulLevels) {
    let availableEssense = 0;
    const inGameEssense = await getInGameEssense();

    availableEssense = inGameEssense;

    // Calculate total essence value of all current souls
    let currentSoulsTotal = 0;
    for (let i = 0; i < currentSoulLevels.length; i++) {
        const level = currentSoulLevels[i];
        if (level >= 0 && level < soulEssense.length) {
            currentSoulsTotal += soulEssense[level].total;
        }
    }
    
    // Add current souls total to available essence
    availableEssense += currentSoulsTotal;
    
    // Calculate total essence required for desired levels
    let desiredSoulsTotal = 0;
    for (let i = 0; i < desiredSoulLevels.length; i++) {
        const level = desiredSoulLevels[i];
        if (level >= 0 && level < soulEssense.length) {
            desiredSoulsTotal += soulEssense[level].total;
        }
    }
    
    console.log("Current souls total essence value: " + currentSoulsTotal);
    console.log("Desired souls total essence required: " + desiredSoulsTotal);
    console.log("Available essense: " + availableEssense);
    
    return availableEssense >= desiredSoulsTotal;
}

function calcGemCost(currentSouls, activeLoadout) {
    let totalCost = 0;
    for (let i = 0; i < 8; i++) {
        const currentLevel = currentSouls[i];
        const desiredLevel = activeLoadout[i];
        if (desiredLevel < currentLevel) {
            totalCost += 500;
        }
    }
    return totalCost;
}

function getInGameEssense() {
    return new Promise((resolve, reject) => {
        const POLL_MS = 50;
        let interval = null;
        let killed = false;

        function kill(originalIS) {
            if (killed) return;
            killed = true;
            if (interval) {
                clearInterval(interval);
                interval = null;
            }
            if (originalIS) {
                window.IS = originalIS;
            }
        }

        interval = setInterval(() => {
            if (typeof window.IS !== "function") return;

            clearInterval(interval);
            interval = null;

            const originalIS = window.IS;

            window.IS = function () {
                const result = originalIS.apply(this, arguments);

                if (
                    result &&
                    typeof result.getGoodsCountByGoodsGtid === "function"
                ) {
                    try {
                        const amount = result.getGoodsCountByGoodsGtid(1020);
                        resolve(amount);
                    } catch (e) {
                        reject(e);
                    } finally {
                        // self-destruct
                        kill(originalIS);
                    }
                }

                return result;
            };
        }, POLL_MS);
    });
}


window.logLoadout = logLoadout;
window.logSoulLevelComparison = logSoulLevelComparison;

