import os
import sys
import datetime
from datetime import timedelta

from io import BytesIO
from PIL import Image, ImageDraw, ImageFont

sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

from src.display_settings import display
from src.global_settings import A, I, FA, fa, icon, LAYOUT, SIZE, COLOR, warning_range

from src.epaper import convertHatB
from src.txt2image import putTxt
from src.ismuggy import isMuggy
from src.weather import getWeather


def getSize(name):
    size_factor = 1
    return int(SIZE[name] * size_factor)


def setColor(name, current_value):
    if current_value > warning_range[name]['max'] or current_value < warning_range[name]['min']:
        COLOR[name] = 'red'
    else:
        COLOR[name] = 'black'


def getColor(name):
    try:
        clr = COLOR[name]
    except KeyError:
        clr = COLOR['default']
    return clr


def outputImg(parameter, img):

    print('Content-Type: image/' + parameter['content_type'])

    img = img.resize(parameter['target_size'])
    if parameter['rotate'] is not None:
        img = img.rotate(parameter['rotate'], expand=True)

    if parameter['content_type'] == 'hat-b':
        out_bytes = convertHatB(img)
        print('Content-Length: {}'.format(len(out_bytes)))
        print()  # end header
        final_out = BytesIO(out_bytes)
    else:
        final_out = BytesIO()
        img.save(final_out, parameter['content_type'])
        final_out.seek(0)
        print() # end header
    sys.stdout.buffer.write(final_out.read())


def returnErrImg(parameter, err_txt):
    width = parameter['width']
    bg_color = 'red'
    txt_color = 'black'
    img = Image.new(parameter['mode'], parameter['target_size'], bg_color)
    draw = ImageDraw.Draw(img)
    y = LAYOUT['BORDER_TOP']
    (pos_x, pos_y) = putTxt(draw, (LAYOUT['BORDER_LEFT'], y), parameter['info'], (A, getSize('info')), txt_color)

    txt_color = 'white'

    y = pos_y + LAYOUT['LINE_SPACE']
    (pos_x, pos_y) = putTxt(draw, (LAYOUT['BORDER_LEFT'], y), icon['error'], (I, getSize('err_title')), txt_color)
    putTxt(draw, (LAYOUT['BORDER_LEFT'] + pos_x, y), " Error", (A, getSize('err_title')), txt_color,
           width - LAYOUT['BORDER_RIGHT'])
    y = pos_y + LAYOUT['LINE_SPACE']
    putTxt(draw, (LAYOUT['BORDER_LEFT'], y), err_txt, (A, getSize('err_txt')), txt_color,
           width - LAYOUT['BORDER_RIGHT'])

    outputImg(parameter, img)
    return


def createTheImage(parameter, data):

    width = parameter['width']
    width_split = int(width / 2) + LAYOUT['BORDER_MID']
    bg_color = 'white'
    img = Image.new(parameter['mode'], parameter['target_size'], bg_color)
    draw = ImageDraw.Draw(img)
    y = LAYOUT['BORDER_TOP']

# title row
    (pos_x, _) = putTxt(draw,
                        (LAYOUT['BORDER_LEFT'] + 2, 2 + y - getSize('info')),
                        icon['refresh'],
                        (I, int(getSize('info') * 1.8)),
                        getColor('info'))
    (pos_x, pos_y) = putTxt(draw,
                        (pos_x + 2, y),
                        '   ' + parameter['info'],
                        (A, getSize('info')),
                        getColor('info'))
    try:
        (pos_x, _) = putTxt(draw,
                        (pos_x, y),
                        ' {2.1f}'.format(data['weather']['current']['temp']),
                        (A, getSize('info')),
                        getColor('info'))
        (pos_x, _) = putTxt(draw,
                        (pos_x - 1 , y - 1),
                        icon['celsius'],
                        (I, getSize('data_unit')),
                        getColor('temperature'))
    except:
        pass
    (pos_x, _) = putTxt(draw,
                        (width_split, y-2),
                        icon['measured'],
                        (I, getSize('info')),
                        getColor('measured'))
    putTxt(draw,
                        (pos_x, y),
                        ' ' + data['measured_value'],
                        (A, getSize('info')),
                        getColor('measured'))
# temperature row
    y = pos_y + LAYOUT['LINE_SPACE']
    (pos_x, _) = putTxt(draw,
                        (LAYOUT['BORDER_LEFT'], y - 1),
                        icon['temperature_out'],
                        (I, getSize('data_value') - 1),
                        getColor('temperature_out'))
    (pos_x, _) = putTxt(draw,
                        (LAYOUT['BORDER_LEFT'] + 3.5, y - 1),
                        icon['temperature_in'],
                        (I, getSize('data_value') - 1),
                        getColor('temperature_in'))
    (pos_x, pos_y) = putTxt(draw,
                        (LAYOUT['BORDER_LEFT'], y),
                        '   {:=+5.1f}'.format(data['temperature']) + ' ',
                        (A, getSize('data_value')),
                        getColor('temperature'))
    (pos_x, _) = putTxt(draw,
                        (pos_x - 1 , y - 1),
                        icon['celsius'],
                        (I, getSize('data_unit') * 1.5),
                        getColor('temperature'))

    (pos_x, _) = putTxt(draw,
                        (width_split, y),
                        icon['humidity'],
                        (I, getSize('data_unit')),
                        getColor('humidity'))
    (pos_x, _) = putTxt(draw,
                        (pos_x, y),
                        '{:2.0f} '.format(data['humidity']),
                        (A, getSize('data_value')),
                        getColor('humidity'))

    (pos_x, _) = putTxt(draw,
                        (pos_x, y),
                        icon['barometer'],
                        (I, getSize('data_unit')),
                        getColor('barometer'))
    (pos_x, pos_y) = putTxt(draw,
                        (pos_x, y),
                        '{:4.0f}'.format(data['BME280_pressure'] / 100),
                        (A, getSize('data_value')),
                        getColor('barometer'))
    putTxt(draw,
                        (pos_x, pos_y - getSize('data_unit')),
                        'hPa',
                        (A, getSize('data_unit')),
                        getColor('barometer'))
# indoor row
    if (parameter['indoor_temperature'] is not None or parameter['indoor_humidity'] is not None
            or parameter['indoor_pressure'] is not None):
        y = pos_y + LAYOUT['LINE_SPACE']
        (pos_x, _) = putTxt(draw,
                        (LAYOUT['BORDER_LEFT'], y + 6),
                        fa['home'],
                        (FA, getSize('data_unit')),
                        getColor('indoor_temperature'))
        if parameter['indoor_temperature'] is not None:
            (pos_x, _) = putTxt(draw,
                            (LAYOUT['BORDER_LEFT'], y),
                            '   {:=+5.1f}'.format(parameter['indoor_temperature']) + ' ',
                            (A, getSize('data_value')),
                            getColor('indoor_temperature'))
            (pos_x, pos_y) = putTxt(draw,
                            (pos_x, y),
                            icon['celsius'],
                            (I, getSize('data_unit') * 1.5),
                            getColor('indoor_temperature'))
        if parameter['indoor_humidity'] is not None:
            (pos_x, _) = putTxt(draw,
                            (width_split, y),
                            icon['humidity'],
                            (I, getSize('data_unit')),
                            getColor('indoor_humidity'))
            (pos_x, pos_y) = putTxt(draw,
                            (pos_x, y),
                            '{:2.0f} '.format(parameter['indoor_humidity']),
                            (A, getSize('data_value')),
                            getColor('indoor_humidity'))

        if parameter['indoor_pressure'] is not None:
            dif = (data['BME280_pressure'] / 100) - (parameter['indoor_pressure'])
            setColor('indoor_pressure', float(dif))
            (pos_x, _) = putTxt(draw,
                            (pos_x, y),
                            icon['barometer'],
                            (I, getSize('data_unit')),
                            getColor('indoor_pressure'))
            (pos_x, pos_y) = putTxt(draw,
                            (pos_x, y),
                            '{:4.0f}'.format(parameter['indoor_pressure'] ),
                            (A, getSize('data_value')),
                            getColor('indoor_pressure'))
            putTxt(draw,
                            (pos_x, pos_y - getSize('data_unit')),
                            'hPa',
                            (A, getSize('data_unit')),
                            getColor('indoor_pressure'))

# solaredge
    if data['power'] is not None:
        y = pos_y + LAYOUT['LINE_SPACE']
        if data['power'] < warning_range['solar']['min']:
            solar_icon = icon['moon']
            solar_color = 'red'
        elif data['power'] < warning_range['solar']['mid1']:
            solar_icon = icon['horizon']
            solar_color = 'red'
        elif data['power'] < warning_range['solar']['mid2']:
            solar_icon = icon['cloudy']
            solar_color = 'black'
        elif data['power'] < warning_range['solar']['max']:
            solar_icon = icon['sun-cloudy']
            solar_color = 'black'
        else:
            solar_icon = icon['sunny']
            solar_color = 'black'

        (pos_x, _) = putTxt(draw,
                    (LAYOUT['BORDER_LEFT'], y - 2),
                    solar_icon,
                    (I, getSize('data_value')),
                    solar_color)
        (pos_x, pos_y) = putTxt(draw,
                    (pos_x, y),
                    '{:4.0f}'.format(data['power']),
                    (A, getSize('data_value')),
                    solar_color)
        (pos_x, _) = putTxt(draw,
                    (pos_x, y + getSize('data_value') - getSize('data_unit')),
                    'W',
                    (A, getSize('data_unit')),
                    solar_color)
        (pos_x, _) = putTxt(draw,
                    (width_split, y),
                    '{:.2f}'.format(data['energy_today'] / 1000),
                    (A, getSize('data_value')),
                    solar_color)
        (pos_x, _) = putTxt(draw,
                    (pos_x, y + getSize('data_value') - getSize('data_unit')),
                    'KW (heute)',
                    (A, getSize('data_unit')),
                    solar_color)


# Victron battery
    if 'soc' in parameter and parameter['soc'] is not None:
        y = pos_y + LAYOUT['LINE_SPACE']
        soc = parameter['soc']
        setColor('soc', float(soc))
        (pos_x, _) = putTxt(draw,
                        (pos_x, y),
                        icon['soc'],
                        (I, getSize('data_unit')),
                        getColor('soc'))

#weather forecast
    y = pos_y + LAYOUT['LINE_SPACE']
    (solar_icon, solar_color) = getWeather(data['weather']['hourly'][1], data['weather']['current'])
    (pos_x, pos_y) = putTxt(draw,
                (LAYOUT['BORDER_LEFT'], y - 2),
                solar_icon,
                (I, getSize('data_value')),
                solar_color)
    (pos_x, _) = putTxt(draw,
                (pos_x, y + getSize('data_value') - getSize('data_unit')),
                '1h  ',
                (A, getSize('data_unit')),
                solar_color)
    (solar_icon, solar_color) = getWeather(data['weather']['hourly'][2], data['weather']['current'])
    (pos_x, _) = putTxt(draw,
                (pos_x, y - 2),
                solar_icon,
                (I, getSize('data_value')),
                solar_color)
    (pos_x, _) = putTxt(draw,
                (pos_x, y + getSize('data_value') - getSize('data_unit')),
                '2h  ',
                (A, getSize('data_unit')),
                solar_color)

    (solar_icon, solar_color) = getWeather(data['weather']['hourly'][3], data['weather']['current'])
    (pos_x, _) = putTxt(draw,
                (pos_x, y - 2),
                solar_icon,
                (I, getSize('data_value')),
                solar_color)
    (pos_x, _) = putTxt(draw,
                (pos_x, y + getSize('data_value') - getSize('data_unit')),
                '3h  ',
                (A, getSize('data_unit')),
                solar_color)

    (solar_icon, solar_color) = getWeather(data['weather']['daily'][1])
    (pos_x, _) = putTxt(draw,
                (pos_x, y - 2),
                solar_icon,
                (I, getSize('data_value')),
                solar_color)
    (pos_x, _) = putTxt(draw,
                (pos_x, y + getSize('data_value') - getSize('data_unit')),
                '1d  ',
                (A, getSize('data_unit')),
                solar_color)
    (solar_icon, solar_color) = getWeather(data['weather']['daily'][2])
    (pos_x, _) = putTxt(draw,
                (pos_x, y - 2),
                solar_icon,
                (I, getSize('data_value')),
                solar_color)
    (pos_x, _) = putTxt(draw,
                (pos_x, y + getSize('data_value') - getSize('data_unit')),
                '2d',
                (A, getSize('data_unit')),
                solar_color)

    # smoke row
    y = pos_y + LAYOUT['LINE_SPACE'] + 1
    (pos_x, _) = putTxt(draw,
                        (LAYOUT['BORDER_LEFT'], y -4),
                        icon['smog'],
                        (I, getSize('data_value')),
                        getColor('SDS'))
    (pos_x, pos_y) = putTxt(draw,
                        (pos_x, y),
                        '{:5.1f}'.format(data['SDS_P2']),
                        (A, getSize('data_value')),
                        getColor('SDS_P2'))
    putTxt(draw,
                        (pos_x, y),
                        ' µg/m³\n (2.5µm)',
                        (A, getSize('data_unit') / 1.5),
                        getColor('SDS_P2'))

    (pos_x, _) = putTxt(draw,
                        (width_split, y),
                        '{:.1f}'.format(data['SDS_P1']),
                        (A, getSize('data_value')),
                        getColor('SDS_P1'))
    putTxt(draw,
                        (pos_x, y),
                        ' µg/m³\n (10µm)',
                        (A, getSize('data_unit') / 1.5),
                        getColor('SDS_P1'))

    outputImg(parameter, img)
    return


#############################################
#
if __name__ == '__main__': #pragma no cover
    print('No executable')
    exit(-1)
