#pragma once

#include "LibLsp/lsp/lsp_diagnostic.h"
#include "LibLsp/lsp/AbsolutePath.h"
#include "LibLsp/lsp/textDocument/did_change.h"
#include "LibLsp/lsp/textDocument/did_close.h"
#include "LibLsp/lsp/textDocument/did_open.h"
#include <mutex>
#include <string>
#include <memory>
#include "Directory.h"

struct WorkingFiles;
struct WorkingFilesData;
struct WorkingFile
{

    int version = 0;
    AbsolutePath filename;
    Directory directory;
    WorkingFiles& parent;
    std::atomic<long long> counter;
    WorkingFile(WorkingFiles&, AbsolutePath const& filename, std::string const& buffer_content);
    WorkingFile(WorkingFiles&, AbsolutePath const& filename, std::string&& buffer_content);
    std::string const& GetContentNoLock() const
    {
        return buffer_content;
    }

protected:
    friend struct WorkingFiles;
    std::string buffer_content;
};

struct WorkingFiles
{

    WorkingFiles();
    ~WorkingFiles();

    void CloseFilesInDirectory(std::vector<Directory> const&);
    std::shared_ptr<WorkingFile> OnOpen(lsTextDocumentItem& open);
    std::shared_ptr<WorkingFile> OnChange(lsTextDocumentDidChangeParams const& change);
    bool OnClose(lsTextDocumentIdentifier const& close);
    std::shared_ptr<WorkingFile> OnSave(lsTextDocumentIdentifier const& _save);

    bool GetFileBufferContent(AbsolutePath const& filename, std::wstring& out)
    {
        auto file = GetFileByFilename(filename);
        if (!file)
        {
            return false;
        }
        return GetFileBufferContent(file, out);
    }
    bool GetFileBufferContent(AbsolutePath const& filename, std::string& out)
    {
        auto file = GetFileByFilename(filename);
        if (!file)
        {
            return false;
        }
        return GetFileBufferContent(file, out);
    }
    bool GetFileBufferContent(std::shared_ptr<WorkingFile>&, std::string& out);
    bool GetFileBufferContent(std::shared_ptr<WorkingFile>&, std::wstring& out);

    // Find the file with the given filename.
    std::shared_ptr<WorkingFile> GetFileByFilename(AbsolutePath const& filename);

    void Clear();

private:
    std::shared_ptr<WorkingFile> GetFileByFilenameNoLock(AbsolutePath const& filename);

    WorkingFilesData* d_ptr;
};