#include "PCH.h"
#include "PapyrusInterface.h"
#include "ScreenCapture.h"
#include "logger.h"

namespace PapyrusInterface {
    
    // Global state
    std::atomic<bool> g_isRunning{false};
    std::atomic<bool> g_cancelFlag{false};
    std::atomic<bool> g_resultReady{false};  // New flag for polling
    std::mutex g_resultMutex;
    std::string g_result = "Success";
    
    // Helper: Convert string to lowercase
    std::string ToLowerCase(const std::string& str) {
        std::string lower = str;
        std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
        return lower;
    }
    
    // Helper: Validate path
    bool IsValidPath(const std::string& pathStr) {
        try {
            std::filesystem::path path(pathStr);
            
            // Check if path is absolute
            if (!path.is_absolute()) {
                logger::warn("Path is not absolute: {}", pathStr);
                return false;
            }
            
            // Check for illegal characters (Windows specific)
            const std::string illegal = "<>:\"|?*";
            std::string filename = path.filename().string();
            if (filename.find_first_of(illegal) != std::string::npos) {
                logger::warn("Path contains illegal characters: {}", pathStr);
                return false;
            }
            
            // Try to create directory if it doesn't exist
            std::filesystem::path dir = path.parent_path();
            if (!std::filesystem::exists(dir)) {
                if (!std::filesystem::create_directories(dir)) {
                    logger::warn("Failed to create directory: {}", dir.string());
                    return false;
                }
            }
            
            // Check write permissions by trying to create a temp file
            std::filesystem::path testFile = dir / ".printscreen_test";
            std::ofstream test(testFile);
            if (!test.good()) {
                logger::warn("No write permission for path: {}", dir.string());
                return false;
            }
            test.close();
            std::filesystem::remove(testFile);
            
            return true;
        }
        catch (const std::exception& e) {
            logger::error("Path validation error: {}", e.what());
            return false;
        }
    }
    
    // Worker thread function (simplified - no ModEvent)
    void CaptureWorkerThread(
        std::string basePath,
        std::string imageType,
        float jpgCompression,
        std::string compressionMode,
        float gifMultiFrameDuration
    ) {
        logger::info("Capture worker thread started");
        logger::info("Parameters: basePath={}, imageType={}, jpgCompression={}, compressionMode={}, gifDuration={}",
                    basePath, imageType, jpgCompression, compressionMode, gifMultiFrameDuration);
        
        // Convert to wide string for Windows APIs
        std::wstring wBasePath(basePath.begin(), basePath.end());
        
        // Setup capture parameters
        ScreenCapture::CaptureParams params;
        params.basePath = wBasePath;
        params.format = ScreenCapture::StringToImageFormat(imageType);
        params.jpegQuality = jpgCompression;
        params.cancelFlag = &g_cancelFlag;
        
        // Set GIF duration correctly
        if (params.format == ScreenCapture::ImageFormat::GIF_MULTIFRAME) {
            params.gifDuration = gifMultiFrameDuration;
            if (params.gifDuration <= 0.0f || params.gifDuration > 30.0f) {
                params.gifDuration = 3.0f; // Default 3 seconds
            }
        }
        
        // Parse compression mode
        if (params.format == ScreenCapture::ImageFormat::TIF) {
            params.tiffMode = ScreenCapture::StringToTiffCompression(compressionMode);
        }
        else if (params.format == ScreenCapture::ImageFormat::DDS) {
            params.ddsMode = ScreenCapture::StringToDDSCompression(compressionMode);
        }
        
        // Perform capture
        auto result = ScreenCapture::CaptureScreen(params);
        
        // Update global result (no ModEvent - just set flags for polling)
        {
            std::lock_guard<std::mutex> lock(g_resultMutex);
            if (g_cancelFlag.load()) {
                g_result = "Cancelled";
            }
            else {
                g_result = result.message;
            }
            g_isRunning = false;
            g_resultReady = true;  // Signal that result is ready
        }
        
        logger::info("Capture completed with result: {}", g_result);
    }
    
    // Papyrus: TakePhoto (Latent)
    RE::BSFixedString TakePhoto(
        RE::StaticFunctionTag*,
        RE::BSFixedString basePath,
        RE::BSFixedString imageType,
        float jpgCompression,
        RE::BSFixedString compressionMode,
        float gifMultiFrameDuration
    ) {
        std::lock_guard<std::mutex> lock(g_resultMutex);
        
        // Check if already running
        if (g_isRunning.load()) {
            g_result = "Already running";
            logger::warn("TakePhoto called while capture already running");
            return RE::BSFixedString(g_result.c_str());
        }
        
        // Convert parameters to lowercase
        std::string basePathStr = ToLowerCase(basePath.c_str());
        std::string imageTypeStr = ToLowerCase(imageType.c_str());
        std::string compressionModeStr = ToLowerCase(compressionMode.c_str());
        
        // Validate parameters
        if (basePathStr.empty()) {
            g_result = "Invalid base path: empty";
            logger::error("{}", g_result);
            return RE::BSFixedString(g_result.c_str());
        }
        
        // Validate image type
        std::vector<std::string> validTypes = {
            "png", "jpg", "jpeg", "bmp", "tif", "tiff", 
            "gif", "gif_multiframe", "gif_multi", "dds"
        };
        
        if (std::find(validTypes.begin(), validTypes.end(), imageTypeStr) == validTypes.end()) {
            g_result = "Invalid image type: " + imageTypeStr;
            logger::error("{}", g_result);
            return RE::BSFixedString(g_result.c_str());
        }
        
        // Validate JPEG compression (0-100)
        if ((imageTypeStr == "jpg" || imageTypeStr == "jpeg") && 
            (jpgCompression < 0.0f || jpgCompression > 100.0f)) {
            g_result = "Invalid JPEG compression: must be 0-100";
            logger::error("{}", g_result);
            return RE::BSFixedString(g_result.c_str());
        }
        
        // Validate GIF duration (1-30 seconds)
        if ((imageTypeStr == "gif_multiframe" || imageTypeStr == "gif_multi") &&
            (gifMultiFrameDuration < 1.0f || gifMultiFrameDuration > 30.0f)) {
            g_result = "Invalid GIF duration: must be 1-30 seconds";
            logger::error("{}", g_result);
            return RE::BSFixedString(g_result.c_str());
        }
        
        // Reset flags
        g_cancelFlag = false;
        g_isRunning = true;
        g_resultReady = false;  // Clear the ready flag
        g_result = "Started";
        
        // Start worker thread with correct parameters
        std::thread captureThread(
            CaptureWorkerThread,
            basePathStr,
            imageTypeStr,
            jpgCompression,
            compressionModeStr,
            gifMultiFrameDuration
        );
        captureThread.detach();
        
        logger::info("TakePhoto started capture thread");
        return RE::BSFixedString(g_result.c_str());
    }
    
    // Papyrus: Get_Result (Enhanced for polling)
    RE::BSFixedString Get_Result(RE::StaticFunctionTag*) {
        std::lock_guard<std::mutex> lock(g_resultMutex);
        
        // Check if we have a new result ready
        if (g_resultReady.load()) {
            g_resultReady = false;  // Reset flag so we only trigger once
            
            // Return special callback codes that Papyrus can detect
            if (g_result == "Success") {
                logger::info("Returning callback: Success");
                return RE::BSFixedString("CALLBACK_SUCCESS");
            } else if (g_result == "Cancelled") {
                logger::info("Returning callback: Cancelled");
                return RE::BSFixedString("CALLBACK_CANCELLED");
            } else {
                // Error case - prefix with CALLBACK_ERROR:
                std::string errorResult = "CALLBACK_ERROR:" + g_result;
                logger::info("Returning callback: {}", errorResult);
                return RE::BSFixedString(errorResult.c_str());
            }
        }
        
        // No new result - return current status
        if (g_isRunning.load()) {
            return RE::BSFixedString("Running");
        }
        
        // Return last result
        return RE::BSFixedString(g_result.c_str());
    }
    
    // Papyrus: Cancel (Non-Latent)
    bool Cancel(RE::StaticFunctionTag*) {
        if (!g_isRunning.load()) {
            logger::warn("Cancel called but no capture is running");
            return false;
        }
        
        g_cancelFlag = true;
        logger::info("Capture cancellation requested");
        return true;
    }
    
    // Papyrus: CheckPath (Non-Latent)
    bool CheckPath(RE::StaticFunctionTag*, RE::BSFixedString path) {
        std::string pathStr = ToLowerCase(path.c_str());
        
        if (pathStr.empty()) {
            logger::warn("CheckPath called with empty path");
            return false;
        }
        
        bool valid = IsValidPath(pathStr);
        logger::info("CheckPath('{}') = {}", pathStr, valid);
        return valid;
    }
    
    // Register all Papyrus functions
    bool RegisterFunctions(RE::BSScript::IVirtualMachine* vm) {
        if (!vm) {
            logger::error("Virtual machine is null");
            return false;
        }
        
        // Register functions with the script name
        const char* scriptName = "PrintScreen_Formula_Script";
        
        // TakePhoto - Latent function
        vm->RegisterFunction(
            "TakePhoto",
            scriptName,
            TakePhoto
        );
        vm->SetCallableFromTasklets(scriptName, "TakePhoto", true);
        
        // Get_Result - Non-Latent (enhanced for polling)
        vm->RegisterFunction(
            "Get_Result",
            scriptName,
            Get_Result
        );
        
        // Cancel - Non-Latent
        vm->RegisterFunction(
            "Cancel",
            scriptName,
            Cancel
        );
        
        // CheckPath - Non-Latent
        vm->RegisterFunction(
            "CheckPath",
            scriptName,
            CheckPath
        );
        
        logger::info("Papyrus functions registered successfully for polling method");
        return true;
    }
}