// SPDX-FileCopyrightText: 2024-2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

#ifndef ANYTHING_BASE_EVENT_HANDLER_H_
#define ANYTHING_BASE_EVENT_HANDLER_H_

#include <filesystem>
#include <glib.h>
#include <gio/gio.h>

#include "common/anything_fwd.hpp"
#include "common/fs_event.h"
#include "core/file_index_manager.h"
#include "core/thread_pool.h"
#include "core/config.h"

ANYTHING_NAMESPACE_BEGIN

enum class index_job_type : char {
    add, remove, update, scan, recursive_update, init_scan, refresh,
    commit_volatile_index,
    commit_persistent_index
};

struct index_job {
    std::string src;
    std::optional<std::string> dst;
    index_job_type type;

    index_job(std::string src, index_job_type type, std::optional<std::string> dst = std::nullopt)
        : src(std::move(src)), dst(std::move(dst)), type(type) {}
};

ANYTHING_NAMESPACE_END

class base_event_handler
{
public:
    base_event_handler(const event_handler_config &config);
    virtual ~base_event_handler();

    virtual void handle(anything::fs_event *event) = 0;
    virtual void start_handle_init_scan(const std::string &path) = 0;

    void terminate_processing();
    void set_index_invalid_and_restart();
    virtual bool handle_config_change(const std::string &key, const event_handler_config &new_config);

    static gboolean trigger_commit_persistent_index(base_event_handler *handler);

protected:
    void set_batch_size(std::size_t size);

    void add_index_delay(std::string path);
    void remove_index_delay(std::string path);
    void update_index_delay(std::string src, std::string dst);
    void scan_index_delay(std::string path);
    void recursive_update_index_delay(std::string src, std::string dst);
    void init_scan_index_delay(std::string path);
    void refresh_indexes();
    void init_refresh_scan_indexes(std::vector<std::string>& index_dirs);

private:
    void eat_jobs(std::vector<anything::index_job>& jobs, std::size_t number);
    void eat_job(const anything::index_job& job);
    void check_jobs_load();

    void jobs_push(std::string src, anything::index_job_type type, std::optional<std::string> dst = std::nullopt);

    void timer_worker(int64_t interval);

    bool scan_directory(const std::string& dir_path, std::function<bool(const std::string&)> handler);

    // 防止竞态条件
    std::vector<std::string> get_blacklist_paths();
    void set_blacklist_paths(const std::vector<std::string> &paths);

private:
    event_handler_config config_;
    anything::file_index_manager index_manager_;
    std::size_t batch_size_;
    std::vector<anything::index_job> jobs_;
    anything::thread_pool pool_;
    GCancellable *cancellable_;
    std::mutex jobs_mtx_;
    std::thread timer_;

    bool index_dirty_;
    int commit_volatile_index_timeout_;

    anything::index_status index_status_;

    std::atomic<bool> stop_scan_directory_;

    std::mutex config_access_mtx_;

    gint batch_count_;

    bool wait_commit_persistent_index_;
};

#endif // ANYTHING_BASE_EVENT_HANDLER_H_
