/*
    Copyright: 2020 Rasmus Thomsen <oss@cogitri.dev>
    SPDX-License-Identifier: GPL-3.0-or-later
*/

use serde::{
    ser::{SerializeStruct, Serializer},
    Serialize,
};
use std::fmt;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ApkRepository {
    pub enabled: bool,
    pub description: Option<String>,
    pub url: String,
}

impl ApkRepository {
    pub fn new(enabled: bool, description: Option<String>, url: String) -> Self {
        ApkRepository {
            enabled,
            description,
            url,
        }
    }
}

impl fmt::Display for ApkRepository {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let enabled_str = if self.enabled { "enabled" } else { "disabled" };
        write!(
            f,
            "{} repository {} originating from file {:?}",
            enabled_str, self.url, self.description
        )
    }
}

impl Serialize for ApkRepository {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut state = serializer.serialize_struct("ApkRepository", 3)?;
        state.serialize_field("enabled", &self.enabled)?;
        state.serialize_field(
            "description",
            &self.description.as_ref().unwrap_or(&"".to_string()),
        )?;
        state.serialize_field("url", &self.url)?;
        state.end()
    }
}

#[cfg(test)]
mod test {
    use super::ApkRepository;
    use serde_test::{assert_ser_tokens, Token};

    #[test]
    fn test_apk_repository_serialize() {
        let repo = ApkRepository {
            enabled: true,
            description: Some("/etc/apk/repositories".to_string()),
            url: "https://example.org".to_string(),
        };
        assert_ser_tokens(
            &repo,
            &[
                Token::Struct {
                    name: "ApkRepository",
                    len: 3,
                },
                Token::Str("enabled"),
                Token::Bool(true),
                Token::Str("description"),
                Token::Str("/etc/apk/repositories"),
                Token::Str("url"),
                Token::Str("https://example.org"),
                Token::StructEnd,
            ],
        );
    }

    #[test]
    fn test_apk_repository_serialize_no_description() {
        let repo = ApkRepository {
            enabled: true,
            description: None,
            url: "https://example.org".to_string(),
        };
        assert_ser_tokens(
            &repo,
            &[
                Token::Struct {
                    name: "ApkRepository",
                    len: 3,
                },
                Token::Str("enabled"),
                Token::Bool(true),
                Token::Str("description"),
                Token::Str(""),
                Token::Str("url"),
                Token::Str("https://example.org"),
                Token::StructEnd,
            ],
        );
    }
}
