from typing import Dict, List, Any, Optional

import httpx
import typing
from lxml import etree as lxmletree

from travelogues_extraction.dataextractors.namespaces import namespaces
from travelogues_extraction.getrecords.session import RecordRetriever
from travelogues_extraction.dataextractors.abstract import AbstractParentAsSecondCast, AbstractXpathJoinDirectlyToColumn


class Werktitel(AbstractParentAsSecondCast):

    def __init__(self, *args, **kwargs):
        AbstractParentAsSecondCast.__init__(self, *args, **kwargs)

    column: str = 'Werktitel'

    log: List[Dict[str, Any]]
    parend_titles: Dict[str, str]
    upper_level_join_string = ' .- '
    lower_level_join_string = ' ; '

    session: httpx.AsyncClient

    werktitel_xpaths = (
        lxmletree.XPath(
            './marc:datafield[@tag="240" and @ind1="1" and @ind2="0" and marc:subfield[@code="a"]]',
            namespaces=namespaces),
        lxmletree.XPath(
            './marc:datafield[@tag="240" and @ind1="1" and @ind2="0" and marc:subfield[@code="t"]]',
            namespaces=namespaces),
        lxmletree.XPath(
            './marc:datafield[@tag="130" and @ind1="0" and marc:subfield[@code="a"]]',
            namespaces=namespaces),
        lxmletree.XPath(
            './marc:datafield[@tag="130" and @ind1="0" and marc:subfield[@code="t"]]',
            namespaces=namespaces),
    )

    subfield_xpaths = [
        lxmletree.XPath(f'./marc:subfield[@code="{code}" or @code="f" or @code="0"]', namespaces=namespaces)
        for code in ('a', 't', 'a', 't')
    ]

    parent_ac_xpath = lxmletree.XPath(
        './marc:datafield[@tag="773" and @ind1="0" and @ind2="8"]/marc:subfield[@code="w"]',
        namespaces=namespaces)

    async def _write(self, record: 'RecordRetriever.Record') -> Optional[str]:
        contents = []
        werktitel_fields = [xpath(record.lxmlelement) for xpath in self.werktitel_xpaths]
        for werktitel_field, subbfield_xpath in zip(werktitel_fields, self.subfield_xpaths):
            if len(werktitel_field) == 0:
                continue
            sub_contents = []
            for e in werktitel_field:
                """
                This is not really a list: Eveytime one item. However, if there would be more items => treat as flat list
                """
                sub_contents += subbfield_xpath(e)

            if len(sub_contents) > 0:
                contents.append(
                    self.lower_level_join_string.join([sub_content.text for sub_content in sub_contents]))

        if len(contents) > 0:
            content = self.upper_level_join_string.join(contents)
            self.target_dataframe.at[record.ac_number, self.column] = content
            return content


class Schlagworte(AbstractParentAsSecondCast):

    def __init__(self, *args, **kwargs):
        AbstractParentAsSecondCast.__init__(self, *args, **kwargs)

    column: str = 'Schlagworte'
    join_string = AbstractXpathJoinDirectlyToColumn.join_string  # to lazy for multi inheritance
    parent_ac_xpath = lxmletree.XPath(
        (
        './marc:datafield['
            '(@tag="773" and @ind1="0" and @ind2="8")'
            ' or '
            '(@tag="830" and @ind1=" " and @ind2="0")'
        ']/marc:subfield[@code="w"]'
        ),
        namespaces=namespaces)
    xpath = lxmletree.XPath('./marc:datafield[@tag="689"]/marc:subfield[@code="a"]', namespaces=namespaces)

    async def _write(self, record: 'RecordRetriever.Record') -> typing.Optional[str]:
        return await AbstractXpathJoinDirectlyToColumn.write(self, record)


