// SPDX-FileCopyrightText: 2022 Lars Wirzenius <liw@liw.fi>
// SPDX-FileCopyrightText: 2024 David Runge <dave@sleepmap.de>
// SPDX-License-Identifier: MIT OR Apache-2.0

use serde::Serialize;

use crate::{OutputBuilder, OutputFormat, OutputVariant, OutputVersion, output::OpgpCardError};

#[derive(Default, Debug, Serialize)]
pub struct List {
    idents: Vec<String>,
    idents_only: bool,
}

impl List {
    pub fn idents_only(&mut self, no_heading: bool) {
        self.idents_only = no_heading;
    }

    pub fn push(&mut self, ident: String) {
        self.idents.push(ident);
    }

    fn text(&self) -> Result<String, OpgpCardError> {
        let s = if self.idents.is_empty() {
            "No OpenPGP cards found.\n".into()
        } else {
            let mut s = "".to_string();

            if !self.idents_only {
                s.push_str("Available OpenPGP cards:\n");
            }

            for id in self.idents.iter().map(|x| x.as_str()) {
                s.push_str(id);
                s.push('\n');
            }
            s
        };
        Ok(s)
    }

    fn v0(&self) -> Result<ListV0, OpgpCardError> {
        Ok(ListV0 {
            schema_version: ListV0::VERSION,
            idents: self.idents.clone(),
        })
    }
}

impl OutputBuilder for List {
    type Err = OpgpCardError;

    fn print(&self, format: OutputFormat, version: OutputVersion) -> Result<String, Self::Err> {
        match format {
            OutputFormat::Json => {
                let result = if ListV0::VERSION.is_acceptable_for(&version) {
                    self.v0()?.json()
                } else {
                    return Err(Self::Err::UnknownVersion(version));
                };
                result.map_err(Self::Err::SerdeJson)
            }
            OutputFormat::Yaml => {
                let result = if ListV0::VERSION.is_acceptable_for(&version) {
                    self.v0()?.yaml()
                } else {
                    return Err(Self::Err::UnknownVersion(version));
                };
                result.map_err(Self::Err::SerdeYaml)
            }
            OutputFormat::Text => Ok(self.text()?),
        }
    }
}

#[derive(Debug, Serialize)]
struct ListV0 {
    schema_version: OutputVersion,
    idents: Vec<String>,
}

impl OutputVariant for ListV0 {
    const VERSION: OutputVersion = OutputVersion::new(0, 11, 0);
}
