#pragma once

#ifdef __linux__

#include "IWindowTracker.hpp"
#include <string>
#include <cstdio>
#include <memory>
#include <array>
#include <fstream>
#include <chrono>

namespace celuna {

/**
 * @brief Linux X11 implementation of window tracking
 *
 * Uses xdotool and /proc for tracking (avoids X11 library dependency).
 * Falls back gracefully if tools are not available.
 */
class X11WindowTracker : public IWindowTracker {
public:
    X11WindowTracker() {
        // Check if xdotool is available
        m_available = (system("which xdotool > /dev/null 2>&1") == 0);
    }

    ~X11WindowTracker() override = default;

    std::string getCurrentAppName() override {
        if (!m_available) return "";

        // Get PID of active window
        std::string pid = executeCommand("xdotool getactivewindow getwindowpid 2>/dev/null");
        if (pid.empty()) return "";

        // Trim newline
        while (!pid.empty() && (pid.back() == '\n' || pid.back() == '\r')) {
            pid.pop_back();
        }

        // Read process name from /proc
        std::string procPath = "/proc/" + pid + "/comm";
        std::ifstream procFile(procPath);
        if (procFile.is_open()) {
            std::string name;
            std::getline(procFile, name);
            return name;
        }

        return "";
    }

    std::string getCurrentWindowTitle() override {
        if (!m_available) return "";

        std::string title = executeCommand("xdotool getactivewindow getwindowname 2>/dev/null");
        // Trim newline
        while (!title.empty() && (title.back() == '\n' || title.back() == '\r')) {
            title.pop_back();
        }
        return title;
    }

    bool isUserIdle(int thresholdSeconds) override {
        return getIdleTimeSeconds() >= thresholdSeconds;
    }

    int getIdleTimeSeconds() override {
        // Try xprintidle if available
        std::string result = executeCommand("xprintidle 2>/dev/null");
        if (!result.empty()) {
            try {
                // xprintidle returns milliseconds
                long ms = std::stol(result);
                return static_cast<int>(ms / 1000);
            } catch (...) {}
        }

        // Fallback: track time since last process change
        auto now = std::chrono::steady_clock::now();
        std::string currentApp = getCurrentAppName();

        if (currentApp != m_lastApp) {
            m_lastApp = currentApp;
            m_lastActivityTime = now;
        }

        auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(
            now - m_lastActivityTime).count();
        return static_cast<int>(elapsed);
    }

    bool isAvailable() const override {
        return m_available;
    }

    std::string getPlatformName() const override {
        return "x11";
    }

private:
    bool m_available = false;
    std::string m_lastApp;
    std::chrono::steady_clock::time_point m_lastActivityTime = std::chrono::steady_clock::now();

    std::string executeCommand(const std::string& cmd) {
        std::array<char, 256> buffer;
        std::string result;

        std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
        if (!pipe) return "";

        while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
            result += buffer.data();
        }

        return result;
    }
};

} // namespace celuna

#endif // __linux__
