#pragma once
#include "./basic_types.hpp"
#include "./document_sync.hpp"
#include "./progress.hpp"

namespace lsp::protocol
{
    enum class DiagnosticSeverity
    {
        Error = 1,
        Warning = 2,
        Information = 3,
        Hint = 4
    };

    enum class DiagnosticTag
    {
        Unnecessary = 1,
        Deprecated = 2
    };

    struct DiagnosticRelatedInformation
    {
        Location location;
        string message;
    };

    struct CodeDescription
    {
        string href;
    };

    struct Diagnostic
    {
        Range range;
        std::optional<DiagnosticSeverity> severity;
        std::optional<integer> code;
        std::optional<string> codeDescription;
        std::optional<string> source;
        std::variant<string, MarkupContent> message;
        std::optional<std::vector<DiagnosticTag>> tags;
        std::optional<std::vector<DiagnosticRelatedInformation>> relatedInformation;
        std::optional<LSPAny> data;
    };

    struct ClientDiagnosticsTagOptions
    {
        std::vector<DiagnosticTag> valueSet;
    };

    struct DiagnosticClientCapabilities
    {
        std::optional<boolean> dynamicRegistration;
        std::optional<boolean> relatedDocumentSupport;
        std::optional<boolean> relatedInformation;
        std::optional<ClientDiagnosticsTagOptions> tagSupport;
        std::optional<boolean> codeDescriptionSupport;
        std::optional<boolean> markupMessageSupport;
        std::optional<boolean> dataSupport;
    };

    struct DiagnosticOptions : WorkDoneProgressOptions
    {
        std::optional<string> identifier;
        boolean interFileDependencies;
        boolean workspaceDiagnostics;
    };
    struct DiagnosticRegistrationOptions : TextDocumentRegistrationOptions, DiagnosticOptions, StaticRegistrationOptions
    {
    };
    struct DiagnosticParams : WorkDoneProgressParams, PartialResultParams
    {
        TextDocumentIdentifier textDocument;
        std::optional<string> identifier;
        std::optional<string> previousResultId;
    };

    struct PublishDiagnosticsClientCapabilities : DiagnosticClientCapabilities
    {
        std::optional<boolean> versionSupport;
    };

    struct PublishDiagnosticsParams
    {
        DocumentUri uri;
        std::optional<integer> version;
        std::vector<Diagnostic> diagnostics;
    };

    using DocumentDiagnosticReportKind = std::string_view;
    namespace DocumentDiagnosticReportKindLiterals
    {
        inline constexpr DocumentDiagnosticReportKind Full = "full";
        inline constexpr DocumentDiagnosticReportKind Unchanged = "unchanged";
    }

    struct FullDocumentDiagnosticReport
    {
        DocumentDiagnosticReportKind kind = DocumentDiagnosticReportKindLiterals::Full;
        std::optional<string> resultId;
        std::vector<Diagnostic> items;
    };

    struct UnchangedDocumentDiagnosticReport
    {
        DocumentDiagnosticReportKind kind = DocumentDiagnosticReportKindLiterals::Unchanged;
        std::optional<string> resultId;
    };

    struct RelatedFullDocumentDiagnosticReport : FullDocumentDiagnosticReport
    {
        std::optional<std::map<string, std::variant<FullDocumentDiagnosticReport, UnchangedDocumentDiagnosticReport>>> relatedDocuments;
    };

    struct RelatedUnchangedDocumentDiagnosticReport : UnchangedDocumentDiagnosticReport
    {
        std::optional<std::map<string, std::variant<FullDocumentDiagnosticReport, UnchangedDocumentDiagnosticReport>>> relatedDocuments;
    };

    struct DocumentDiagnosticReportPartialResult
    {
        std::optional<std::map<string, std::variant<FullDocumentDiagnosticReport, UnchangedDocumentDiagnosticReport>>> relatedDocuments;
    };

    using DocumentDiagnosticReport = std::variant<RelatedFullDocumentDiagnosticReport, RelatedUnchangedDocumentDiagnosticReport>;

    struct DiagnosticServerCancellationData
    {
        std::optional<boolean> retriggerRequest;
    };

    struct PreviousResultId
    {
        DocumentUri uri;
        string value;
    };

    struct WorkspaceDiagnosticParams : WorkDoneProgressParams, PartialResultParams
    {
        std::optional<string> identifier;
        std::vector<PreviousResultId> previousResultIds;
    };

    struct WorkspaceFullDocumentDiagnosticReport : FullDocumentDiagnosticReport
    {
        DocumentUri uri;
        std::optional<integer> version;
    };

    struct WorkspaceUnchangedDocumentDiagnosticReport : UnchangedDocumentDiagnosticReport
    {
        DocumentUri uri;
        std::optional<integer> version;
    };

    using WorkspaceDocumentDiagnosticReport = std::variant<WorkspaceFullDocumentDiagnosticReport, WorkspaceUnchangedDocumentDiagnosticReport>;
    struct WorkspaceDiagnosticReport
    {
        std::vector<WorkspaceDocumentDiagnosticReport> items;
    };

    struct WorkspaceDiagnosticReportPartialResult
    {
        std::vector<WorkspaceDocumentDiagnosticReport> items;
    };

    struct DiagnosticWorkspaceClientCapabilities
    {
        std::optional<boolean> refreshSupport;
    };

}
