use crate::parser::XmlReader;
use crate::XmlError;
use crate::XmlResult;

use arrayvec::ArrayString;
use beef::lean::Cow;
use core::ops::Deref;
use core::str::FromStr;
use iban::Iban;
use isin::ISIN;
use iso_currency::Country;
use iso_currency::Currency;
use isolang::Language;
use lei::LEI;
use quick_xml::events::BytesStart;
use uuid::Uuid;

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct CurrencyCode(Currency);

impl CurrencyCode {
    pub(crate) fn parse(reader: &mut XmlReader<'_>, start: &BytesStart) -> XmlResult<Self> {
        let code = reader.expect_text()?;

        Self::from_str(&code)
    }
}

impl FromStr for CurrencyCode {
    type Err = XmlError;

    fn from_str(code: &str) -> Result<Self, Self::Err> {
        Currency::from_code(code)
            .map(Self)
            .ok_or_else(|| -> XmlError { todo!() })
    }
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct BicIdentifier<'a>(Cow<'a, str>);

impl<'a> BicIdentifier<'a> {
    pub(crate) fn parse(reader: &mut XmlReader<'a>, _start: &BytesStart<'_>) -> XmlResult<Self> {
        let bic = reader.expect_text()?;

        Ok(Self(bic))
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct CountryCode(Country);

impl CountryCode {
    pub(crate) fn parse(reader: &mut XmlReader, start: &BytesStart) -> XmlResult<Self> {
        let code = reader.expect_text()?;

        let code = Country::from_str(&code).map_err(|_| -> XmlError { todo!() })?;

        Ok(Self(code))
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct IbanIdentifier(Iban);

impl IbanIdentifier {
    pub(crate) fn parse(reader: &mut XmlReader<'_>, _start: &BytesStart<'_>) -> XmlResult<Self> {
        let iban = reader.expect_text()?;

        let iban = Iban::from_str(&iban).unwrap();

        Ok(Self(iban))
    }
}

impl Deref for IbanIdentifier {
    type Target = Iban;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct IsinIdentifier(ISIN);

impl IsinIdentifier {
    pub(crate) fn parse(reader: &mut XmlReader<'_>, _start: &BytesStart<'_>) -> XmlResult<Self> {
        let isin = reader.expect_text()?;
        let isin = ISIN::from_str(&isin).unwrap();

        Ok(Self(isin))
    }
}

impl Deref for IsinIdentifier {
    type Target = ISIN;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct IsoLanguageCode(Language);

impl IsoLanguageCode {
    pub(crate) fn parse(reader: &mut XmlReader<'_>, _start: &BytesStart<'_>) -> XmlResult<Self> {
        let code = reader.expect_text()?;

        Language::from_639_1(&code).map(Self).ok_or_else(|| todo!())
    }
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct LeiIdentifier(LEI);

impl LeiIdentifier {
    pub(crate) fn parse(reader: &mut XmlReader<'_>, _start: &BytesStart<'_>) -> XmlResult<Self> {
        let lei = reader.expect_text()?;

        let lei = LEI::from_str(&lei).unwrap();

        Ok(Self(lei))
    }
}

impl Deref for LeiIdentifier {
    type Target = LEI;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct UuidV4Identifier(pub Uuid);

impl UuidV4Identifier {
    pub(crate) fn parse(reader: &mut XmlReader<'_>, _start: &BytesStart<'_>) -> XmlResult<Self> {
        let uuid = reader.expect_text()?;

        let uuid = Uuid::try_parse(&uuid).unwrap();

        Ok(Self(uuid))
    }
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct SupplementaryDataEnvelope1 {}

impl SupplementaryDataEnvelope1 {
    pub(crate) fn parse(reader: &mut XmlReader<'_>, _start: &BytesStart<'_>) -> XmlResult<Self> {
        Ok(Self {})
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ExternalCardTransactionCategory1Code(ArrayString<4>);

impl ExternalCardTransactionCategory1Code {
    pub(crate) fn parse(reader: &mut XmlReader<'_>, _start: &BytesStart<'_>) -> XmlResult<Self> {
        let code = reader.expect_text()?;

        let code = ArrayString::try_from(&*code).unwrap();

        Ok(Self(code))
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ExternalCreditLineType1Code(ArrayString<4>);

impl ExternalCreditLineType1Code {
    pub(crate) fn parse(reader: &mut XmlReader<'_>, _start: &BytesStart<'_>) -> XmlResult<Self> {
        let code = reader.expect_text()?;

        let code = ArrayString::try_from(&*code).unwrap();

        Ok(Self(code))
    }
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ExternalFinancialInstitutionIdentification1Code(ArrayString<4>);

impl ExternalFinancialInstitutionIdentification1Code {
    pub(crate) fn parse(reader: &mut XmlReader<'_>, _start: &BytesStart<'_>) -> XmlResult<Self> {
        let code = reader.expect_text()?;

        let code = ArrayString::try_from(&*code).unwrap();

        Ok(Self(code))
    }
}