// Copyright (C) 2024 Philipp Hofer
//
// Licensed under the EUPL, Version 1.2 or - as soon they will be approved by
// the European Commission - subsequent versions of the EUPL (the "Licence").
// You may not use this work except in compliance with the Licence.
//
// You should have received a copy of the European Union Public License along
// with this program.  If not, you may obtain a copy of the Licence at:
// <https://joinup.ec.europa.eu/software/page/eupl>
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the Licence is distributed on an "AS IS" basis,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the Licence for the specific language governing permissions and
// limitations under the Licence.

use std::iter::Peekable;

use roxmltree::{Children, Node};

use crate::law::Content;

use super::{liste::Liste, table::Table, AbsatzAbs, Expect};

#[derive(Debug, PartialEq)]
pub(crate) struct Absatz {
    pub(crate) content: String,
    pub(crate) typ: String,
}
impl Absatz {
    pub(crate) fn test_with_typ(n: &Node, typ: &str) -> bool {
        n.tag_name().name() == "absatz" && n.attribute("typ") == Some(typ)
    }

    // Parses one logical 'Absatz'. If there's a List or Table after the Absatz, RIS assumes this
    // one to be included in the paragraph
    //
    // # Returns
    // - String: (optional) paragraph id
    // - Content: content of the paragraph
    pub(crate) fn parse_full(c: &mut Peekable<Children>) -> (Option<String>, Content) {
        let absatz = AbsatzAbs::parse(c.next().unwrap());
        let par_id = absatz.gldsym;

        let mut content = Vec::new();
        content.push(Content::Text(absatz.content));

        // If there's a  "liste" after an "absatz", the "liste" should be part of the "absatz"
        while let Some(child) = c.peek() {
            if Liste::test(child) {
                let liste = Liste::parse_full(c).content;
                content.extend(liste);
            } else if Table::test(child) {
                // If there's a  "table" after an "absatz", the "table" should be part of the "absatz"
                let table = Table::parse_full(c);
                content.extend(table.iter().cloned());
            } else if Absatz::test_with_typ(child, "satz")
                || Absatz::test_with_typ(child, "erltext")
            {
                // After a 'absatz' there can be a '<absatz typ="[satz|erltext]"' which should be part of the first absatz
                // (e.g. 1209 ABGB)
                content.push(Content::Text(Absatz::parse(c.next().unwrap()).content));
            } else {
                break;
            }
        }
        if content.len() == 1 {
            (par_id, content[0].clone())
        } else {
            (par_id, Content::Multi(content))
        }
    }

    pub(crate) fn parse(n: Node) -> Self {
        Expect::from(&n).tag("absatz");

        let typ = n.attribute("typ").unwrap().into();

        let mut content = String::new();
        // Get text from this element + all direct childs
        for c in n.children() {
            if let Some(text) = c.text() {
                content.push_str(text);
            }
        }

        Self { content, typ }
    }
}
