use serde::{Deserialize, Serialize};
use serde_json::Value;
use serde_repr::{Deserialize_repr, Serialize_repr};

use crate::{Range, prelude::TextDocumentIdentifier};

#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct PublishDiagnosticsParams {
    pub uri: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub version: Option<i32>,
    pub diagnostics: Vec<Diagnostic>,
}

#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct DocumentDiagnosticParams {
    #[serde(rename = "textDocument")]
    pub text_document: TextDocumentIdentifier,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub identifier: Option<String>,
    #[serde(rename = "previousResultId", skip_serializing_if = "Option::is_none")]
    pub previous_result_id: Option<String>,
}

#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct DocumentDiagnosticReport {
    pub kind: String, // "full" | "unchanged"
    #[serde(rename = "resultId", skip_serializing_if = "Option::is_none")]
    pub result_id: Option<String>,
    pub items: Vec<Diagnostic>,
}

#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Diagnostic {
    pub range: Range,
    pub severity: Option<DiagnosticSeverity>,
    pub code: Option<String>,
    #[serde(rename = "codeDescription")]
    pub code_description: Option<CodeDescription>,
    pub source: Option<String>,
    pub message: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tags: Option<Vec<DiagnosticTag>>,
    #[serde(rename = "relatedInformation")]
    pub related_information: Option<Vec<DiagnosticRelatedInformation>>,
    pub data: Option<Value>,
}

#[repr(i32)]
#[derive(Clone, Debug, PartialEq, Serialize_repr, Deserialize_repr)]
pub enum DiagnosticSeverity {
    Error = 1,
    Warning = 2,
    Information = 3,
    Hint = 4,
}

#[repr(i32)]
#[derive(Clone, Debug, PartialEq, Serialize_repr, Deserialize_repr)]
pub enum DiagnosticTag {
    Unnecessary = 1,
    Deprecated = 2,
}

#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct CodeDescription {
    pub href: String,
}

#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct DiagnosticRelatedInformation {
    pub location: Location,
    pub message: String,
}

#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Location {
    pub uri: String,
    pub range: Range,
}
