import typing
import re as regex

import httpx
import pandas as pd
import pytest

from travelogues_extraction.getrecords.session import RecordRetriever
from travelogues_extraction.getrecords.acnumber_extractor import extract_ac_from_series
from travelogues_extraction.dataextractors.dataextractors.simple import VolltextAndBarcode, Ausgabe, Verlagsort, \
    VerlegerDrucker, Erscheinungsjahr, ErscheinungsjahrSortierform, Kollation, Illustrationen, Format, Anmerkungen, \
    Sprache, OriginalSprache, BemerkungenZurSprache, Standardnummer, ArtDesInhalts, Inhalt, Marker, Zusammenstellung, \
    Standort, VD17

from travelogues_extraction.dataextractors.dataextractors.index import IndexSetter

dummy_data = pd.read_excel('test/dummy_data/TravelogueD18_ALMAoutput_20200707.xlsx')
barcode_regex = regex.compile(r'Z\d{8}')


@pytest.mark.asyncio
async def test_volltext_and_barcode_and_ausgabe_and_verlagsort_and_verleger_drucker_and_more():
    reduced_series = dummy_data['Datensatznummer'][:25]
    session = httpx.AsyncClient()
    record_retriever = RecordRetriever(extract_ac_from_series(reduced_series), session=session)
    target_dataframe = pd.DataFrame([], columns=
    [IndexSetter.column, ] + VolltextAndBarcode.get_columns_names_I_work_on() + [Ausgabe.column, Verlagsort.column, VerlegerDrucker.column,
     Erscheinungsjahr.column, ErscheinungsjahrSortierform.column, ] + Illustrationen.get_columns_names_I_work_on() \
    + [Format.column, ] + Anmerkungen.get_columns_names_I_work_on() + [Sprache.column, OriginalSprache.column,
   BemerkungenZurSprache.column, ArtDesInhalts.column, Inhalt.column, Zusammenstellung.column, Standort.column, ]
                                    )
    index_setter = IndexSetter(target_dataframe)
    volltext_and_barcode = VolltextAndBarcode(target_dataframe)
    ausgabe = Ausgabe(target_dataframe)
    verlagsort = Verlagsort(target_dataframe)
    verleger_drucker = VerlegerDrucker(target_dataframe)
    erscheinungsjahr = Erscheinungsjahr(target_dataframe)
    erscheinungsjahr_sort = ErscheinungsjahrSortierform(target_dataframe)
    kollation = Kollation(target_dataframe)
    illustrationen = Illustrationen(target_dataframe)
    format = Format(target_dataframe)
    anmerkungen = Anmerkungen(target_dataframe)
    sprache = Sprache(target_dataframe)
    originalsprache = OriginalSprache(target_dataframe)
    bemerkungenZurSprache = BemerkungenZurSprache(target_dataframe)
    artDesInhalts = ArtDesInhalts(target_dataframe)
    inhalt = Inhalt(target_dataframe)
    marker = Marker(target_dataframe)
    zusammenstellung = Zusammenstellung(target_dataframe)
    standort = Standort(target_dataframe)

    index = 0
    stop = 3

    korrekte_verlagsorte = ['Hamburg', 'Wien', 'Nürnberg und Leipzig,', ]

    verleger_drucker_korrekt = [
        ['bei Benjamin Gottlob Hoffmann', 'gedruckt bey Johann Georg Langhoff'],
        ['gedruckt und verlegt bey F. A. Schrämbl', ],
        ['bey Christoph Weigel und Schneider', ],
    ]

    kollation_korrekt = [
        'LVIII, das heißt LVI Seiten,  494 Seiten,  3 ungezähltes Blätter Bildtafeln, 3 ungezählte gefaltete Blätter Bildtafeln',
        'XXX Seiten, 6 ungezählte Seiten, 231, das heißt 331 Seiten, 5 ungezählte Blätter Bildtafeln, 1 ungezähltes gefaltetes Blatt Karte',
        '16 ungezählte Seiten, 392 Seiten, 7 ungezählte gefaltete Blätter',
        '24 ungezählte Seiten, 364 Seiten, 10 ungezählte Seiten, 11 ungezählte gefaltete Blätter Bildtafeln',
        '6 ungezählte Seiten, 521 Seiten, 1 ungezähltes gefaltetes Blatt',
        '14 ungezählte Seiten, 380 Seiten, 12 ungezählte Seiten',
        'XVI, 352 Seiten, 4 ungezählte gefaltete Blätter Bildtafeln',
        '32 ungezählte Seiten, 428 Seiten, 20 ungezählte Seiten, 2 ungezählte gefaltete Blätter',
    ]

    illustrationen_korrekt = ['5 Illustrationen, 1 Karte',
                                '5 Illustrationen, 1 Karte',
                                '2 Karten',
                                '9 Illustrationen, 2 Karten',
                                '2 Illustrationen',
                                None,
                                '5 Illustrationen',
                                '2 Karten',
                                '7 Illustrationen',
                                ]
    anmerkungen_korrekt = [
        [
            'Die Illustrationen sind 3 Kupfersti',
            'Bibliografischer Nachwei',
            'Blatt a2a-a5b (Seite IV',
            None,
        ],
        [
            'Die Illustrationen sind', 'Bibliografischer Nachweis: Bibliografie', 'Seite III-XXX: Vorrede von Johan',]
    ]

    zusatz_anmerkungen = {'AC09836279': 'Signaturformel: a8, b4, )(8, )( )( 4, A-Z8, Aa3 (Ex. ON'}


    async for record in record_retriever.generate_records():
        await index_setter.write(record)
        await volltext_and_barcode.write(record)
        await ausgabe.write(record)
        await verlagsort.write(record)
        await verleger_drucker.write(record)
        await erscheinungsjahr.write(record)
        await erscheinungsjahr_sort.write(record)
        await kollation.write(record)
        await illustrationen.write(record)
        await format.write(record)
        await anmerkungen.write(record)
        await sprache.write(record)
        await originalsprache.write(record)
        await bemerkungenZurSprache.write(record)
        await artDesInhalts.write(record)
        await inhalt.write(record)
        await marker.write(record)
        await zusammenstellung.write(record)
        await standort.write(record)

        assert target_dataframe.shape[0] == index + 1
        assert target_dataframe.iat[index, 1].__class__ is str
        assert target_dataframe.iat[index, 2].__class__ is str
        assert target_dataframe.at[record.ac_number, verlagsort.column] == korrekte_verlagsorte[index]

        ausgabe_val = target_dataframe.iat[index, 3]

        if index == 2:
            assert ausgabe_val.__class__ is str
            assert ausgabe_val == 'Zweite Ausgabe'
        else:
            assert ausgabe_val.__class__ is float
            assert ausgabe_val.__repr__() == 'nan'

        assert target_dataframe['Barcode'].str.contains(barcode_regex).sum() == index + 1
        assert target_dataframe['Volltext'].str.startswith('http').sum() == index + 1

        systemnummer = target_dataframe.iat[index, 0]
        volltext = target_dataframe.at[systemnummer, 'Volltext']
        volltexte = volltext.split(volltext_and_barcode.join_string)
        assert all([volltext.startswith('http') for volltext in volltexte])
        barcodes = target_dataframe.at[systemnummer, 'Barcode'].split(volltext_and_barcode.join_string)
        assert len(barcodes) == len(volltexte)

        verleger_drucker_list = target_dataframe.at[record.ac_number, verleger_drucker.column].split(
            verleger_drucker.join_string)
        assert verleger_drucker_list == verleger_drucker_korrekt[index]

        assert target_dataframe.at[record.ac_number, erscheinungsjahr.column].startswith('17')

        erscheinungsjahr_sort_val: str = target_dataframe.at[record.ac_number, erscheinungsjahr_sort.column]
        assert erscheinungsjahr_sort_val.__class__ is str
        assert erscheinungsjahr_sort_val.__len__() == 4
        assert erscheinungsjahr_sort_val.isdigit()
        assert erscheinungsjahr_sort_val.startswith('17')

        kollation_val = target_dataframe.at[record.ac_number, kollation.column]
        assert kollation_val == kollation_korrekt[index]

        illustrationen_val = target_dataframe.at[record.ac_number, illustrationen.get_columns_names_I_work_on()[0]]
        if illustrationen_korrekt[index] is None:
            assert illustrationen_val.__class__ is float
            assert illustrationen_val.__repr__() == 'nan'
        else:
            assert illustrationen_val.__class__ is str
            assert illustrationen_val == illustrationen_korrekt[index]

        if index == 0:
            assert target_dataframe.at[record.ac_number, illustrationen.get_columns_names_I_work_on()[1]] == '5'
            assert target_dataframe.at[record.ac_number, illustrationen.get_columns_names_I_work_on()[2]] == '1'

        format_val: str = target_dataframe.at[record.ac_number, format.column]
        assert format_val.__class__ is str
        assert format_val == '8°' # now that is simple

        if index < 2:
            anmerkungen_korrekt_hier = anmerkungen_korrekt[index]
            for anmerkung_korrekter_anfang, column in zip(anmerkungen_korrekt_hier, anmerkungen.get_columns_names_I_work_on()[:-1]):
                anmerkung_val: typing.Union[str, float] = target_dataframe.at[record.ac_number, column]
                if anmerkung_korrekter_anfang is None:
                    assert anmerkung_val.__class__ is float
                    assert  anmerkung_val.__repr__() is 'nan'
                else:
                    assert anmerkung_val.__class__ is str
                    assert anmerkung_val.startswith(anmerkung_korrekter_anfang)

        if record.ac_number in zusatz_anmerkungen:
            anmerkung_val: str = target_dataframe.at[record.ac_number, anmerkungen.get_columns_names_I_work_on()[-1]]
            assert anmerkung_val.startswith(zusatz_anmerkungen[record.ac_number])

        sprache_val = target_dataframe.at[record.ac_number, sprache.column]
        assert sprache_val == 'ger' # :-) That#s easy

        originalsprache_val: typing.Union[str, float] = target_dataframe.at[record.ac_number, originalsprache.column]

        if index < 2:
            assert originalsprache_val == 'eng'
        else:
            assert originalsprache_val.__repr__() == 'nan'

        bemerkung_sprache_val: typing.Union[str, float] = target_dataframe.at[record.ac_number, bemerkungenZurSprache.column]
        if index < 2:
            assert bemerkung_sprache_val == 'Aus dem Englischen übersetzt'
        else:
            assert originalsprache_val.__repr__() == 'nan'

        artDesInhalts_val: typing.Union[str, float] = target_dataframe.at[record.ac_number, artDesInhalts.column]
        if index == 1:
            assert artDesInhalts_val == 'Reisebericht'
        elif index == 2:
            assert artDesInhalts_val.__repr__() == 'nan'

        inhalt_val: typing.Union[str, float] = target_dataframe.at[record.ac_number, inhalt.column]
        if index == 0:
            assert inhalt_val.__repr__() == 'nan'
        elif index == 1:
            assert inhalt_val.__class__ == str
            inhalt_list = inhalt_val.split(inhalt.join_string)
            assert len(inhalt_list) == 2
            assert inhalt_list[0][0].isalpha()
            assert inhalt_list[1][0].isalpha()

        markers = target_dataframe.at[record.ac_number, marker.column].split(marker.join_string)
        assert len(markers) > 0
        assert any([m.startswith('Travel') for m in markers])

        if index < 2:
            zusammenstellung_val: typing.Union[str, float] = target_dataframe.at[record.ac_number, zusammenstellung.column]
            if index == 0:
                assert zusammenstellung_val.__repr__() == 'nan'
            else:
                assert zusammenstellung_val.startswith('Zusammenstellung')

        assert target_dataframe.at[record.ac_number, standort.column].startswith('Z')

        index += 1
        if index == stop:
            break


@pytest.mark.asyncio
async def test_standardnummer():
    reduced_series = dummy_data[dummy_data['Datensatznummer'].str.contains('AC09705420') | dummy_data['Datensatznummer'].str.contains('AC10438476')]['Datensatznummer']
    session = httpx.AsyncClient()
    record_retriever = RecordRetriever(extract_ac_from_series(reduced_series), session=session)
    target_dataframe = pd.DataFrame([])
    indexer = IndexSetter(target_dataframe)
    standardnummer = Standardnummer(target_dataframe)
    async for record in record_retriever.generate_records():
        await indexer.write(record)
        await standardnummer.write(record)

    assert target_dataframe.shape == (2, 2)
    assert target_dataframe.at['AC09705420', standardnummer.column] == 'VD18 90551591'
    assert target_dataframe.at['AC10438476', standardnummer.column].__repr__() == 'nan'


@pytest.mark.asyncio
async  def test_vd17():
    # AC07705435   whithout
    # AC09682453   whith
    reduced_series = dummy_data[
        dummy_data['Datensatznummer'].str.contains('AC07705435') | dummy_data['Datensatznummer'].str.contains(
            'AC09682453')]['Datensatznummer']
    session = httpx.AsyncClient()
    record_retriever = RecordRetriever(extract_ac_from_series(reduced_series), session=session)
    target_dataframe = pd.DataFrame([], columns=[IndexSetter.column, VD17.column])
    indexer = IndexSetter(target_dataframe)
    vd17 = VD17(target_dataframe)
    async for record in record_retriever.generate_records():
        await indexer.write(record)
        await vd17.write(record)

    assert target_dataframe.shape == (2, 2)
    assert target_dataframe.at['AC09682453', vd17.column] == 'VD18 14804557'
    assert target_dataframe.at['AC07705435', vd17.column].__repr__() == 'nan'
