-- Pokemon Memory Reader - Main Script
-- This script initializes the application and manages the game detection system
-- Global variables
MemoryReader = {}
MemoryReader.currentGame = nil
MemoryReader.gameAddresses = nil
MemoryReader.isInitialized = false
MemoryReader.partyReader = nil
MemoryReader.playerReader = nil
MemoryReader.server = nil
MemoryReader.serverEnabled = true -- Can be toggled by user

-- Load required modules
local gameDetection = require("core.gamedetection")
local CFRUPartyReader = require("readers.party.cfrupartyreader")

-- Generation Party Readers
local Gen3PartyReader = require("readers.party.gen3partyreader")
local Gen2PartyReader = require("readers.party.gen2partyreader")
local Gen1PartyReader = require("readers.party.gen1partyreader")

-- Generation Player Readers
local Gen3PlayerReader = require("readers.player.gen3playerreader")
local Gen2PlayerReader = require("readers.player.gen2playerreader")
local Gen1PlayerReader = require("readers.player.gen1playerreader")

local gameUtils = require("utils.gameutils")
local debugTools = require("debug.debugtools")
local Server = require("network.server")
local gamesDB = require("data.gamesdb")


-- Initialize the Memory Reader
function MemoryReader.initialize()
    console.log("----- Pokemon Memory Reader -----")
    console.log("Initializing...")
    
    -- Detect the currently loaded game
    local detectedGame = gameDetection.detectGame()
    
    if detectedGame and detectedGame.gameInfo then
        -- Get game name from detected game info
        local gameName = detectedGame.gameInfo.gameName or "Unknown Game"
        console.log("Game found: " .. gameName)
        
        MemoryReader.currentGame = detectedGame
        MemoryReader.isInitialized = true
        
        -- Initialize Readers based on generation
        local generation = detectedGame.gameInfo.generation

        -- CFRU is Generally for Gen3 Rom Hacks
        if generation == "CFRU" then
            MemoryReader.partyReader = CFRUPartyReader:new()
        elseif generation == 3 then
            MemoryReader.partyReader = Gen3PartyReader:new()
            MemoryReader.playerReader = Gen3PlayerReader:new()
        elseif generation == 2 then
            MemoryReader.partyReader = Gen2PartyReader:new()
            MemoryReader.playerReader = Gen2PlayerReader:new()
        elseif generation == 1 then
            MemoryReader.partyReader = Gen1PartyReader:new()
            MemoryReader.playerReader = Gen1PlayerReader:new()
        else
            console.log("Unsupported generation: " .. tostring(generation))
            return false
        end
        
        -- Start HTTP server
        if MemoryReader.serverEnabled then
            MemoryReader.startServer()
        end
        
        return true
    else
        local supportedGames = gameDetection.getSupportedGames()
        console.log("No supported Pokemon game detected!")
        console.log("Supported games: " .. table.concat(supportedGames, ", "))
        return false
    end
end

-- Main update loop (called every frame)
function MemoryReader.update()
    if not MemoryReader.isInitialized then
        return
    end
    
    -- Update HTTP server
    if MemoryReader.server then
        MemoryReader.server:update()
    end
end

-- Get party data based on game generation
function MemoryReader.getPartyData()
    if not MemoryReader.isInitialized then
        console.log("Memory Reader not initialized! Please restart the script.")
        return nil
    end
    
    if not MemoryReader.partyReader then
        console.log("Party reader not available for this game!")
        return nil
    end
    
    -- Read party based on game generation
    local gameCode = MemoryReader.currentGame.gameInfo.gameCode
    local party
    
    if MemoryReader.currentGame.gameInfo.generation == 1 or MemoryReader.currentGame.gameInfo.generation == 2 then
        -- Gen1 and Gen2 use integer addresses directly
        party = MemoryReader.partyReader:readParty(MemoryReader.currentGame.addresses, gameCode)
    else
        -- Gen3 uses partyAddr (string hex format)
        if not MemoryReader.currentGame.addresses.partyAddr then
            console.log("Player party address not available!")
            return nil
        end
        local partyAddr = gameUtils.hexToNumber(MemoryReader.currentGame.addresses.partyAddr)
        party = MemoryReader.partyReader:readParty({partyAddr = partyAddr}, gameCode)
    end
    
    return party
end

-- Server management functions
function MemoryReader.startServer()
    if MemoryReader.server then
        console.log("Server is already running!")
        return true
    end
    
    MemoryReader.server = Server:new(MemoryReader)
    return MemoryReader.server:start()
end

function MemoryReader.stopServer()
    if not MemoryReader.server then
        console.log("Server is not running!")
        return true
    end
    
    local success = MemoryReader.server:stop()
    MemoryReader.server = nil
    return success
end

function MemoryReader.toggleServer()
    if MemoryReader.server then
        MemoryReader.stopServer()
        console.log("Server disabled")
    else
        if MemoryReader.startServer() then
            console.log("Server enabled")
        else
            console.log("Failed to start server")
        end
    end
end

-- Shutdown cleanup
function MemoryReader.shutdown()
    console.log("Pokemon Memory Reader shutting down...")
    
    -- Stop server if running
    if MemoryReader.server then
        MemoryReader.stopServer()
    end
    
    MemoryReader.isInitialized = false
end

-- Register user commands
local UserCommands = require("commands.usercommands")
for name, func in pairs(UserCommands) do
    if type(func) == "function" then
        _G[name] = func
    end
end

-- Initialize on script start
if MemoryReader.initialize() then
    console.log("----- PMR Ready -----")
    console.log("Type help() for a list of commands!")
    
    -- Register event callbacks
    event.onexit(MemoryReader.shutdown)
    
    -- Main execution loop
    while true do
        MemoryReader.update()
        emu.frameadvance()
    end
else
    console.log("Initialization failed!")
end