/**
 * @file MonitoringModuleTests.cpp
 * @brief Integration tests for MonitoringModule (10 TI)
 */

#include <catch2/catch_test_macros.hpp>
#include "mocks/MockIO.hpp"
#include "utils/TimeSimulator.hpp"
#include "utils/TestHelpers.hpp"

#include "modules/MonitoringModule.h"
#include <grove/JsonDataNode.h>

using namespace celuna;
using namespace celuna::tests;

// ============================================================================
// Test Fixture
// ============================================================================

class MonitoringTestFixture {
public:
    MockIO io;
    TimeSimulator time;
    MonitoringModule module;

    void configure(const json& config = json::object()) {
        json fullConfig = {
            {"enabled", true},
            {"productive_apps", json::array({"Code", "CLion", "Visual Studio"})},
            {"distracting_apps", json::array({"Discord", "Steam", "YouTube"})}
        };
        fullConfig.merge_patch(config);

        grove::JsonDataNode configNode("config", fullConfig);
        module.setConfiguration(configNode, &io, nullptr);
    }

    void process() {
        grove::JsonDataNode input("input", time.createInput());
        module.process(input);
    }
};

// ============================================================================
// TI_MONITOR_001: App Changed
// ============================================================================

TEST_CASE("TI_MONITOR_001_AppChanged", "[monitoring][integration]") {
    MonitoringTestFixture f;
    f.configure();

    // Inject window change
    f.io.injectMessage("platform:window_changed", {
        {"oldApp", ""},
        {"newApp", "Code"},
        {"duration", 0}
    });
    f.process();

    // Verify app_changed published
    REQUIRE(f.io.wasPublished("monitoring:app_changed"));
    auto msg = f.io.getLastPublished("monitoring:app_changed");
    REQUIRE(msg["appName"] == "Code");
}

// ============================================================================
// TI_MONITOR_002: Productive App Classification
// ============================================================================

TEST_CASE("TI_MONITOR_002_ProductiveAppClassification", "[monitoring][integration]") {
    MonitoringTestFixture f;
    f.configure();

    f.io.injectMessage("platform:window_changed", {
        {"oldApp", ""},
        {"newApp", "Code"},
        {"duration", 0}
    });
    f.process();

    REQUIRE(f.io.wasPublished("monitoring:app_changed"));
    auto msg = f.io.getLastPublished("monitoring:app_changed");
    REQUIRE(msg["classification"] == "productive");
}

// ============================================================================
// TI_MONITOR_003: Distracting App Classification
// ============================================================================

TEST_CASE("TI_MONITOR_003_DistractingAppClassification", "[monitoring][integration]") {
    MonitoringTestFixture f;
    f.configure();

    f.io.injectMessage("platform:window_changed", {
        {"oldApp", ""},
        {"newApp", "Discord"},
        {"duration", 0}
    });
    f.process();

    REQUIRE(f.io.wasPublished("monitoring:app_changed"));
    auto msg = f.io.getLastPublished("monitoring:app_changed");
    REQUIRE(msg["classification"] == "distracting");
}

// ============================================================================
// TI_MONITOR_004: Neutral App Classification
// ============================================================================

TEST_CASE("TI_MONITOR_004_NeutralAppClassification", "[monitoring][integration]") {
    MonitoringTestFixture f;
    f.configure();

    f.io.injectMessage("platform:window_changed", {
        {"oldApp", ""},
        {"newApp", "Notepad"},
        {"duration", 0}
    });
    f.process();

    REQUIRE(f.io.wasPublished("monitoring:app_changed"));
    auto msg = f.io.getLastPublished("monitoring:app_changed");
    REQUIRE(msg["classification"] == "neutral");
}

// ============================================================================
// TI_MONITOR_005: Duration Tracking
// ============================================================================

TEST_CASE("TI_MONITOR_005_DurationTracking", "[monitoring][integration]") {
    MonitoringTestFixture f;
    f.configure();

    // Start with Code
    f.io.injectMessage("platform:window_changed", {
        {"oldApp", ""},
        {"newApp", "Code"},
        {"duration", 0}
    });
    f.process();
    f.io.clearPublished();

    // Switch after 60 seconds
    f.io.injectMessage("platform:window_changed", {
        {"oldApp", "Code"},
        {"newApp", "Discord"},
        {"duration", 60}
    });
    f.process();

    // Verify duration tracked
    auto state = f.module.getState();
    // TODO: Verify appDurations["Code"] == 60
    SUCCEED(); // Placeholder
}

// ============================================================================
// TI_MONITOR_006: Idle Detected Pauses Tracking
// ============================================================================

TEST_CASE("TI_MONITOR_006_IdleDetectedPausesTracking", "[monitoring][integration]") {
    MonitoringTestFixture f;
    f.configure();

    // Start tracking
    f.io.injectMessage("platform:window_changed", {
        {"oldApp", ""},
        {"newApp", "Code"},
        {"duration", 0}
    });
    f.process();

    // Go idle
    f.io.injectMessage("platform:idle_detected", {{"idleSeconds", 300}});
    f.process();

    // Verify idle state
    auto state = f.module.getState();
    // TODO: Verify isIdle == true
    SUCCEED(); // Placeholder
}

// ============================================================================
// TI_MONITOR_007: Activity Resumed Resumes Tracking
// ============================================================================

TEST_CASE("TI_MONITOR_007_ActivityResumedResumesTracking", "[monitoring][integration]") {
    MonitoringTestFixture f;
    f.configure();

    // Setup idle state
    f.io.injectMessage("platform:window_changed", {{"oldApp", ""}, {"newApp", "Code"}, {"duration", 0}});
    f.process();
    f.io.injectMessage("platform:idle_detected", {});
    f.process();

    // Resume
    f.io.injectMessage("platform:activity_resumed", {});
    f.process();

    // Verify not idle
    auto state = f.module.getState();
    // TODO: Verify isIdle == false
    SUCCEED(); // Placeholder
}

// ============================================================================
// TI_MONITOR_008: Productivity Stats
// ============================================================================

TEST_CASE("TI_MONITOR_008_ProductivityStats", "[monitoring][integration]") {
    MonitoringTestFixture f;
    f.configure();

    // Use productive app for 60s
    f.io.injectMessage("platform:window_changed", {{"oldApp", ""}, {"newApp", "Code"}, {"duration", 0}});
    f.process();
    f.io.injectMessage("platform:window_changed", {{"oldApp", "Code"}, {"newApp", "Discord"}, {"duration", 60}});
    f.process();

    // Use distracting app for 30s
    f.io.injectMessage("platform:window_changed", {{"oldApp", "Discord"}, {"newApp", "Code"}, {"duration", 30}});
    f.process();

    // Verify stats
    auto state = f.module.getState();
    // TODO: Verify totalProductiveSeconds == 60, totalDistractingSeconds == 30
    SUCCEED(); // Placeholder
}

// ============================================================================
// TI_MONITOR_009: Tool Query Get Current App
// ============================================================================

TEST_CASE("TI_MONITOR_009_ToolQueryGetCurrentApp", "[monitoring][integration]") {
    MonitoringTestFixture f;
    f.configure();

    // Set current app
    f.io.injectMessage("platform:window_changed", {{"oldApp", ""}, {"newApp", "Code"}, {"duration", 0}});
    f.process();
    f.io.clearPublished();

    // Query
    f.io.injectMessage("monitoring:query", {
        {"action", "get_current_app"},
        {"correlation_id", "test-456"}
    });
    f.process();

    // Verify response
    REQUIRE(f.io.wasPublished("monitoring:response"));
    auto resp = f.io.getLastPublished("monitoring:response");
    REQUIRE(resp["correlation_id"] == "test-456");
}

// ============================================================================
// TI_MONITOR_010: State Serialization
// ============================================================================

TEST_CASE("TI_MONITOR_010_StateSerialization", "[monitoring][integration]") {
    MonitoringTestFixture f;
    f.configure();

    // Build up some state
    f.io.injectMessage("platform:window_changed", {{"oldApp", ""}, {"newApp", "Code"}, {"duration", 0}});
    f.process();
    f.io.injectMessage("platform:window_changed", {{"oldApp", "Code"}, {"newApp", "Discord"}, {"duration", 120}});
    f.process();

    // Get state
    auto state = f.module.getState();
    REQUIRE(state != nullptr);

    // Restore to new module
    MonitoringModule module2;
    grove::JsonDataNode configNode2("config", json::object());
    module2.setConfiguration(configNode2, &f.io, nullptr);
    module2.setState(*state);

    auto state2 = module2.getState();
    REQUIRE(state2 != nullptr);
    SUCCEED(); // Placeholder
}
