// Tests for fn_ui::file_poll_diff (cpp/functions/core/file_poll_diff).
// Pura: compara dos snapshots de FS y devuelve added/modified/removed.

#define CATCH_CONFIG_MAIN
#include "catch_amalgamated.hpp"

#include "core/file_poll_diff.h"

#include <algorithm>
#include <vector>
#include <string>

using fn_ui::file_poll_diff;
using fn_ui::FileEntry;

namespace {
// Helper: ordena los vectores para comparaciones estables (el orden interno
// depende del orden de iteracion de unordered_map, no es estable).
void sort_diff(fn_ui::FileDiff& d) {
    std::sort(d.added.begin(),    d.added.end());
    std::sort(d.modified.begin(), d.modified.end());
    std::sort(d.removed.begin(),  d.removed.end());
}
}

TEST_CASE("file_poll_diff detects added/modified/removed") {
    std::vector<FileEntry> before = {{"a", 10, 1}, {"b", 20, 2}, {"c", 30, 3}};
    std::vector<FileEntry> after  = {{"a", 10, 1}, {"b", 25, 2}, {"d", 40, 4}};
    auto d = file_poll_diff(before, after);
    sort_diff(d);
    REQUIRE(d.added    == std::vector<std::string>{"d"});
    REQUIRE(d.modified == std::vector<std::string>{"b"});
    REQUIRE(d.removed  == std::vector<std::string>{"c"});
}

TEST_CASE("file_poll_diff: empty inputs") {
    auto d = file_poll_diff({}, {});
    REQUIRE(d.added.empty());
    REQUIRE(d.modified.empty());
    REQUIRE(d.removed.empty());
}

TEST_CASE("file_poll_diff: identical snapshots") {
    std::vector<FileEntry> snap = {{"a", 1, 100}, {"b", 2, 200}};
    auto d = file_poll_diff(snap, snap);
    REQUIRE(d.added.empty());
    REQUIRE(d.modified.empty());
    REQUIRE(d.removed.empty());
}

TEST_CASE("file_poll_diff: all added (before vacio)") {
    std::vector<FileEntry> after = {{"a", 1, 1}, {"b", 2, 2}};
    auto d = file_poll_diff({}, after);
    sort_diff(d);
    REQUIRE(d.added == std::vector<std::string>{"a", "b"});
    REQUIRE(d.modified.empty());
    REQUIRE(d.removed.empty());
}

TEST_CASE("file_poll_diff: all removed (after vacio)") {
    std::vector<FileEntry> before = {{"a", 1, 1}, {"b", 2, 2}};
    auto d = file_poll_diff(before, {});
    sort_diff(d);
    REQUIRE(d.removed == std::vector<std::string>{"a", "b"});
    REQUIRE(d.modified.empty());
    REQUIRE(d.added.empty());
}

TEST_CASE("file_poll_diff: solo size cambia -> modified") {
    std::vector<FileEntry> before = {{"a", 100, 5}};
    std::vector<FileEntry> after  = {{"a", 200, 5}};
    auto d = file_poll_diff(before, after);
    REQUIRE(d.modified == std::vector<std::string>{"a"});
    REQUIRE(d.added.empty());
    REQUIRE(d.removed.empty());
}

TEST_CASE("file_poll_diff: solo mtime cambia -> modified") {
    std::vector<FileEntry> before = {{"a", 100, 5}};
    std::vector<FileEntry> after  = {{"a", 100, 9}};
    auto d = file_poll_diff(before, after);
    REQUIRE(d.modified == std::vector<std::string>{"a"});
    REQUIRE(d.added.empty());
    REQUIRE(d.removed.empty());
}

TEST_CASE("file_poll_diff: combinacion compleja") {
    std::vector<FileEntry> before = {
        {"keep",      10, 1},
        {"mod_size",  20, 2},
        {"mod_mtime", 30, 3},
        {"removed",   40, 4},
    };
    std::vector<FileEntry> after = {
        {"keep",      10, 1},
        {"mod_size",  21, 2},
        {"mod_mtime", 30, 9},
        {"new",       50, 5},
    };
    auto d = file_poll_diff(before, after);
    sort_diff(d);
    REQUIRE(d.added    == std::vector<std::string>{"new"});
    REQUIRE(d.modified == std::vector<std::string>{"mod_mtime", "mod_size"});
    REQUIRE(d.removed  == std::vector<std::string>{"removed"});
}
