use k8s_crds_cert_manager::certificates::{
    Certificate, CertificateIssuerRef, CertificateSpec,
};
use kube::api::ObjectMeta;
use kube::Resource;

use crate::types::webservice::{TlsSpec, WebService};
use crate::types::chatservice::ChatService;

fn slug_host(host: &str) -> String {
    host.replace('.', "-")
}

pub fn build_web_certificate(ws: &WebService) -> Certificate {
    let tls = ws.spec.tls.as_ref().unwrap();
    let oref = ws.controller_owner_ref(&()).unwrap();
    let ns = ws.metadata.namespace.clone().unwrap();
    let slug = slug_host(&ws.spec.host);
    build_certificate_inner(&slug, &ns, tls, oref)
}

pub fn build_chat_certificate(cs: &ChatService) -> Certificate {
    let tls = cs.spec.tls.as_ref().unwrap();
    let oref = cs.controller_owner_ref(&()).unwrap();
    let ns = cs.metadata.namespace.clone().unwrap();
    let slug = slug_host(&cs.spec.host);
    build_certificate_inner(&slug, &ns, tls, oref)
}

fn build_certificate_inner(
    slug: &str,
    ns: &str,
    tls: &TlsSpec,
    oref: k8s_openapi::apimachinery::pkg::apis::meta::v1::OwnerReference,
) -> Certificate {
    Certificate {
        metadata: ObjectMeta {
            name: Some(format!("{slug}-cert")),
            namespace: Some(ns.to_string()),
            owner_references: Some(vec![oref]),
            ..Default::default()
        },
        spec: CertificateSpec {
            secret_name: format!("{slug}-tls"),
            issuer_ref: CertificateIssuerRef {
                name: tls.issuer_ref.name.clone(),
                kind: Some(tls.issuer_ref.kind.clone()),
                group: Some("cert-manager.io".to_string()),
            },
            dns_names: Some(tls.dns_names.clone()),
            ..Default::default()
        },
        status: None,
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::testutil::{test_chatservice, test_webservice};

    #[test]
    fn web_certificate_secret_name_slugified() {
        let cert = build_web_certificate(&test_webservice());
        assert_eq!(cert.spec.secret_name, "txt-irc-now-tls");
    }

    #[test]
    fn web_certificate_name_slugified() {
        let cert = build_web_certificate(&test_webservice());
        assert_eq!(cert.metadata.name.unwrap(), "txt-irc-now-cert");
    }

    #[test]
    fn web_certificate_uses_issuer_from_spec() {
        let cert = build_web_certificate(&test_webservice());
        assert_eq!(cert.spec.issuer_ref.name, "letsencrypt-prod");
        assert_eq!(cert.spec.issuer_ref.kind, Some("ClusterIssuer".to_string()));
    }

    #[test]
    fn web_certificate_has_dns_names() {
        let cert = build_web_certificate(&test_webservice());
        let dns = cert.spec.dns_names.as_ref().unwrap();
        assert_eq!(dns, &["txt.irc.now"]);
    }

    #[test]
    fn web_certificate_has_owner_reference() {
        let cert = build_web_certificate(&test_webservice());
        let orefs = cert.metadata.owner_references.unwrap();
        assert_eq!(orefs[0].name, "txt");
    }

    #[test]
    fn chat_certificate_secret_name_slugified() {
        let cert = build_chat_certificate(&test_chatservice());
        assert_eq!(cert.spec.secret_name, "chat-irc-now-tls");
    }

    #[test]
    fn chat_certificate_has_owner_reference() {
        let cert = build_chat_certificate(&test_chatservice());
        let orefs = cert.metadata.owner_references.unwrap();
        assert_eq!(orefs[0].name, "chat");
    }
}
