use kube::CustomResource;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

#[derive(CustomResource, Serialize, Deserialize, Default, Debug, Clone, JsonSchema)]
#[kube(
    group = "irc.josie.cloud",
    version = "v1alpha1",
    kind = "SojuBouncer",
    namespaced,
    status = "SojuBouncerStatus",
    shortname = "soju",
    printcolumn = r#"{"name":"Hostname", "type":"string", "jsonPath":".spec.hostname"}"#,
    printcolumn = r#"{"name":"Ready", "type":"string", "jsonPath":".status.conditions[?(@.type==\"Ready\")].status"}"#
)]
pub struct SojuBouncerSpec {
    pub hostname: String,
    #[serde(default)]
    pub hostname_cloak: Option<String>,
    #[serde(default)]
    pub title: Option<String>,
    #[serde(default)]
    pub listeners: Vec<Listener>,
    #[serde(default)]
    pub tls: Option<TlsSpec>,
    #[serde(default)]
    pub route: Option<RouteSpec>,
    #[serde(default)]
    pub resources: Option<ResourceRequirements>,
    #[serde(default)]
    pub auth: Option<AuthSpec>,
}

#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema)]
pub struct AuthSpec {
    pub oauth2_url: String,
    #[serde(default)]
    pub secret_ref: Option<String>,
}

#[derive(Serialize, Deserialize, Default, Debug, Clone, JsonSchema)]
pub struct Listener {
    pub address: String,
    #[serde(default)]
    pub tls: bool,
    #[serde(default)]
    pub websocket: bool,
}

#[derive(Serialize, Deserialize, Default, Debug, Clone, JsonSchema)]
pub struct TlsSpec {
    pub issuer_ref: IssuerRef,
    pub dns_names: Vec<String>,
}

#[derive(Serialize, Deserialize, Default, Debug, Clone, JsonSchema)]
pub struct IssuerRef {
    pub name: String,
    pub kind: String,
}

#[derive(Serialize, Deserialize, Default, Debug, Clone, JsonSchema)]
pub struct RouteSpec {
    pub host: String,
}

#[derive(Serialize, Deserialize, Default, Debug, Clone, JsonSchema)]
pub struct ResourceRequirements {
    #[serde(default)]
    pub requests: Option<ResourceList>,
    #[serde(default)]
    pub limits: Option<ResourceList>,
}

#[derive(Serialize, Deserialize, Default, Debug, Clone, JsonSchema)]
pub struct ResourceList {
    #[serde(default)]
    pub memory: Option<String>,
    #[serde(default)]
    pub cpu: Option<String>,
}

#[derive(Serialize, Deserialize, Default, Debug, Clone, JsonSchema)]
pub struct SojuBouncerStatus {
    #[serde(default)]
    pub conditions: Vec<Condition>,
    #[serde(default)]
    pub observed_generation: Option<i64>,
}

#[derive(Serialize, Deserialize, Default, Debug, Clone, JsonSchema)]
pub struct Condition {
    #[serde(rename = "type")]
    pub type_: String,
    pub status: String,
    pub reason: String,
    pub message: String,
    pub last_transition_time: String,
}

#[cfg(test)]
mod tests {
    use super::*;
    use kube::CustomResourceExt;

    #[test]
    fn crd_generates_valid_schema() {
        let crd = SojuBouncer::crd();
        let name = crd.metadata.name.unwrap();
        assert_eq!(name, "sojubouncers.irc.josie.cloud");
    }

    #[test]
    fn default_spec_has_sane_values() {
        let spec = SojuBouncerSpec::default();
        assert!(spec.listeners.is_empty());
        assert!(spec.tls.is_none());
        assert!(spec.route.is_none());
        assert!(spec.resources.is_none());
    }
}
