# encoding=utf-8
import hashlib
from sw.allotmentclub import Member, Organization, User
from sw.allotmentclub.account import import_transactions_from_fints
from sw.allotmentclub.application import Application
import risclog.sqlalchemy.interfaces
import csv
import datetime
import gocept.logging
import os
import lnetatmo
import pyramid.testing
import pyramid.threadlocal
import requests
import transaction
import xml.etree.ElementTree as ET
import zope.component


ORGANIZATION_ID = 1


def import_members():
    parser = gocept.logging.ArgumentParser(
        description="Import members from excel file.")
    parser.add_argument('-c', '--config', default='portal.ini',
                        help='Specify the config file. (default: portal.ini)')
    parser.add_argument(
        '-i', '--input', default='members.xslx',
        help='Specify the input file. (default: members.xslx)')
    options = parser.parse_args()
    app = Application.from_filename(options.config)
    registry = pyramid.registry.Registry(
        bases=(zope.component.getGlobalSiteManager(),))
    config = pyramid.config.Configurator(
        settings=app.settings, registry=registry)
    config.setup_registry(settings=app.settings)
    request = pyramid.testing.DummyRequest(_registry=registry)
    request.client_addr = '127.0.0.1'
    context = pyramid.threadlocal.manager.get().copy()
    context['request'] = request
    context['registry'] = registry
    pyramid.threadlocal.manager.push(context)
    with open(options.input, 'r') as file:
        reader = csv.reader(file, delimiter=';')
        for id, line in enumerate(reader):
            if id == 0:
                continue
            Member.find_or_create(
                title='',
                appellation='Herr',
                organization_id=2,
                lastname=line[0],
                firstname=line[1],
                street=line[2],
                zip=line[3],
                city=line[4],
                country='Deutschland',
                phone=line[5],
                mobile=line[6],
                email=line[7],
                birthday=line[8])
    transaction.commit()


def import_transactions():
    parser = gocept.logging.ArgumentParser(
        description="Import banking transactions.")
    parser.add_argument('-c', '--config', default='portal.ini',
                        help='Specify the config file. (default: portal.ini)')
    options = parser.parse_args()
    app = Application.from_filename(options.config)
    registry = pyramid.registry.Registry(
        bases=(zope.component.getGlobalSiteManager(),))
    config = pyramid.config.Configurator(
        settings=app.settings, registry=registry)
    config.setup_registry(settings=app.settings)
    request = pyramid.testing.DummyRequest(_registry=registry)
    request.client_addr = '127.0.0.1'
    context = pyramid.threadlocal.manager.get().copy()
    context['request'] = request
    context['registry'] = registry
    pyramid.threadlocal.manager.push(context)
    user = User.by_username('system')
    import_transactions_from_fints(user)


VCF_FILES = {
    1: 'sweh',
    2: 'blauerball'
}


def export_members_vcf():
    parser = gocept.logging.ArgumentParser(
        description="Export members in vcf format.")
    parser.add_argument('-c', '--config', default='portal.ini',
                        help='Specify the config file. (default: portal.ini)')
    options = parser.parse_args()
    Application.from_filename(options.config)
    for organization in Organization.query().all():
        output = ""
        for m in (
                Member.query()
                .filter(Member.organization_id == organization.id)
                .filter(Member.leaving_year.is_(None))):
            output += """BEGIN:VCARD
VERSION:3.0
PRODID:-//Sebastian Wehrmann//sw.allotmentclub//DE
N:{lastname};{firstname};;;
FN:{firstname} {lastname}
ADR;type=HOME;type=pref:;;{street};{city};;{zip};{country}""".format(
                lastname=m.lastname, firstname=m.firstname, street=m.street,
                city=m.city, zip=m.zip, country=m.country)
            if m.email:
                output += """
EMAIL;type=INTERNET;type=HOME;type=pref:{}""".format(m.email)
            if m.mobile:
                output += """
TEL;type=CELL;type=VOICE;type=pref:{}""".format(m.mobile)
            if m.phone:
                output += """
TEL;type=HOME;type=VOICE:{}""".format(m.phone)
            if m.birthday:
                output += """
BDAY:{}""".format(m.birthday.strftime('%Y%m%d'))
            if m.allotments:
                output += """
NOTE:Bungalow: {}""".format('/'.join(str(a.number) for a in m.allotments))
            output += """
ORG:{org}
REV:{rev}""".format(org=organization.title,
                    rev=datetime.datetime.now().isoformat())
            output += """
UID:{uid}
X-RADICALE-NAME:{uid}.vcf
END:VCARD
""".format(uid=m.id)
        path = os.path.join(os.path.expanduser("~"),
                            '.config/radicale/collections',
                            VCF_FILES[organization.id])
        if not os.path.exists(path):
            os.makedirs(path)
        with open(os.path.join(path, 'addressbook.vcf'), 'w') as f:
            f.write(output)


def export_events_ics():
    import sw.allotmentclub.browser.calendar
    parser = gocept.logging.ArgumentParser(
        description="Export events in ics format.")
    parser.add_argument('-c', '--config', default='portal.ini',
                        help='Specify the config file. (default: portal.ini)')
    parser.add_argument('-t', '--type', help='The type (Mitglied|Vorstand)')
    options = parser.parse_args()
    assert options.type in ('Mitglied', 'Vorstand')

    queries = {
        'Mitglied': sw.allotmentclub.browser.calendar.MitgliederQuery,
        'Vorstand': sw.allotmentclub.browser.calendar.VorstandQuery
    }

    Application.from_filename(options.config)

    name = (
        'Mitgliederliste' if options.type == 'Mitglied' else 'Vorstandsliste'
    )
    output = f"""\
BEGIN:VCALENDAR
VERSION:2.0
PRODID:VerwaltungLeunaBundalow
X-WR-CALNAME:Leuna-Siedlung {name}
NAME:Leuna-Siedlung Mitgliederliste
CALSCALE:GREGORIAN
BEGIN:VTIMEZONE
TZID:Europe/Berlin
TZURL:http://tzurl.org/zoneinfo-outlook/Europe/Berlin
X-LIC-LOCATION:Europe/Berlin
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
TZNAME:CEST
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
TZNAME:CET
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
END:STANDARD
END:VTIMEZONE
"""

    db = zope.component.getUtility(
        risclog.sqlalchemy.interfaces.IDatabase
    )
    query = queries[options.type](db, None).select()
    for event in query:
        m = hashlib.md5()
        m.update('-'.join(str(i) for i in event).encode())
        uid = m.hexdigest()
        if event[-2]:
            timestamp = event[4].strftime('%Y%m%dT000000Z')
            start = end = event[4].strftime('%Y%m%d')
            if event[5]:
                end = event[5].strftime('%Y%m%d')
        else:
            timestamp = event[4].strftime('%Y%m%dT%H%M%SZ')
            start = end = event[4].strftime('%Y%m%dT%H%M%S')
            if event[5]:
                end = event[5].strftime('%Y%m%dT%H%M%S')
        output += f"""\
BEGIN:VEVENT
DTSTAMP:{timestamp}
UID:{uid}@roter-see.de
DTSTART;TZID=Europe/Berlin:{start}
DTEND;TZID=Europe/Berlin:{end}
SUMMARY:{event[2]}
LOCATION:{event[3]}
END:VEVENT
"""
    output += "END:VCALENDAR"
    print(output)


def grab_helios_data(settings):
    payload = {
        "v00003": "de",
        "v01306": "v01306",
        "v00001": "v00001",
        "v00402": settings['helios.pass'],
        "but0": "Anmelden",
    }

    session_requests = requests.session()

    result = session_requests.post(
        'http://10.0.1.64/info.htm',
        data=payload,
        headers=dict(referer='http://10.0.1.64')
    )

    headers = {
        "Host": "10.0.1.64",
        "User-Agent": ("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:65.0)"
                       " Gecko/20100101 Firefox/65.0"),
        "Accept": "*/*",
        "Accept-Language": "de,en-US;q=0.7,en;q=0.3",
        "Accept-Encoding": "gzip, deflate",
        "Referer": "http://10.0.1.64/anzeig.htm",
        "Referrer-Policy": "no-referrer-when-downgrade",
        "Content-Type": "text/plain;charset=UTF-8",
        "Content-Length": "20",
        "Connection": "keep-alive"}

    result = session_requests.post(
        'http://10.0.1.64/data/werte8.xml',
        headers=headers,
        data="xml=/data/werte8.xml",
    )

    data = dict()
    key = None
    for id, child in enumerate(ET.fromstring(result.text)):
        if id == 0:
            continue
        if key is None:
            key = child
        else:
            data[key.text] = child.text
            key = None

    return data


def grab_netatmo_data(settings):
    result = dict()

    # 1 : Authenticate
    authorization = lnetatmo.ClientAuth(
        settings['netatmo.client.id'],
        settings['netatmo.client.secret'],
        settings['netatmo.user'],
        settings['netatmo.pass'],
        scope="read_station")

    # 2 : Get devices list
    weatherData = lnetatmo.WeatherStationData(authorization)

    # 3 : Access most fresh data directly
    station = weatherData.stationByName('Am Wachtelberg 14 (Wohnzimmer)')
    for module in station['modules']:
        if module['type'] == 'NAModule1':
            result['wachtelberg_temp_out_battery'] = module['battery_percent']
            result['wachtelberg_out_temp'] = (
                module['dashboard_data']['Temperature'])
            result['wachtelberg_out_humi'] = (
                module['dashboard_data']['Humidity'])
            temp_trend = module['dashboard_data']['temp_trend']
            temp_trend = ('right' if temp_trend == 'stable' else temp_trend)
            result['wachtelberg_out_temp_trend'] = temp_trend
        elif module['type'] == 'NAModule3':
            result['wachtelberg_rain_battery'] = module['battery_percent']
            result['wachtelberg_rain'] = module['dashboard_data']['Rain']
            result['wachtelberg_rain_1'] = (
                module['dashboard_data']['sum_rain_1'])
            result['wachtelberg_rain_24'] = (
                module['dashboard_data']['sum_rain_24'])
        elif module['type'] == 'NAModule2':
            result['wachtelberg_wind_battery'] = module['battery_percent']
            result['wachtelberg_wind_strength'] = (
                module['dashboard_data']['WindStrength'])
            result['wachtelberg_wind_angle'] = (
                module['dashboard_data']['WindAngle'])
        elif module['type'] == 'NAModule4':
            result['wachtelberg_temp_in_battery'] = module['battery_percent']
            result['wachtelberg_in_temp'] = (
                module['dashboard_data']['Temperature'])
            result['wachtelberg_in_humi'] = (
                module['dashboard_data']['Humidity'])
            result['wachtelberg_in_co2'] = module['dashboard_data']['CO2']

    station = weatherData.stationByName('Roter See (Wohnzimmer)')
    for module in station['modules']:
        if module['type'] == 'NAModule1':
            result['rotersee_temp_out_battery'] = module['battery_percent']
            result['rotersee_out_temp'] = (
                module['dashboard_data']['Temperature'])
            result['rotersee_out_humi'] = module['dashboard_data']['Humidity']
            temp_trend = module['dashboard_data']['temp_trend']
            temp_trend = ('right' if temp_trend == 'stable' else temp_trend)
            result['rotersee_out_temp_trend'] = temp_trend
        elif module['type'] == 'NAModule3':
            result['rotersee_rain_battery'] = module['battery_percent']
            result['rotersee_rain'] = module['dashboard_data']['Rain']
            result['rotersee_rain_1'] = module['dashboard_data']['sum_rain_1']
            result['rotersee_rain_24'] = (
                module['dashboard_data']['sum_rain_24'])
    result['rotersee_in_temp'] = station['dashboard_data']['Temperature']
    result['rotersee_in_humi'] = station['dashboard_data']['Humidity']
    result['rotersee_in_co2'] = station['dashboard_data']['CO2']
    return result


def grab_dashboard_data():
    from sw.allotmentclub import DashboardData
    parser = gocept.logging.ArgumentParser(
        description="Grab helios data.")
    parser.add_argument('-c', '--config', default='portal.ini',
                        help='Specify the config file. (default: portal.ini)')
    options = parser.parse_args()
    app = Application.from_filename(options.config)
    registry = pyramid.registry.Registry(
        bases=(zope.component.getGlobalSiteManager(),))
    config = pyramid.config.Configurator(
        settings=app.settings, registry=registry)
    config.setup_registry(settings=app.settings)
    request = pyramid.testing.DummyRequest(_registry=registry)
    request.client_addr = '127.0.0.1'
    context = pyramid.threadlocal.manager.get().copy()
    context['request'] = request
    context['registry'] = registry
    pyramid.threadlocal.manager.push(context)

    heliosdata = grab_helios_data(app.settings)
    try:
        netatmodata = grab_netatmo_data(app.settings)
    except Exception:
        netatmodata = dict()

    dashboarddata = DashboardData.create(
        organization_id=ORGANIZATION_ID,
        luefterstufe=heliosdata['v00102'],
        luefter_percent=heliosdata['v00103'],
        luefter_aussenluft=float(heliosdata['v00104']),
        luefter_zuluft=float(heliosdata['v00105']),
        luefter_fortluft=float(heliosdata['v00106']),
        luefter_abluft=float(heliosdata['v00107']),
        luefter_abluft_feuchte=heliosdata['v02136'])

    for k, v in netatmodata.items():
        setattr(dashboarddata, k, v)

    transaction.commit()
