"""Run thermal results from energyplus sql files through comfort models."""

import click
import sys
import logging
import json

from ladybug.epw import EPW
from ladybug.sql import SQLiteResult
from ladybug.datatype.speed import AirSpeed
from ladybug.datatype.energyflux import MetabolicRate
from ladybug.datatype.rvalue import ClothingInsulation

from ladybug_comfort.collection.pmv import PMV
from ladybug_comfort.collection.adaptive import Adaptive

from ._helper import load_data, load_pmv_par_str, load_adaptive_par_str

_logger = logging.getLogger(__name__)


@click.group(help='Commands for running energyplus sql results through comfort models.')
def sql():
    pass


@sql.command('pmv-by-room')
@click.argument('result-sql', type=click.Path(
    exists=True, file_okay=True, dir_okay=False, resolve_path=True))
@click.option('--air-speed', '-v', help='A single number for air speed in m/s or a '
              'string of a JSON array with numbers that align with the result-sql '
              'reporting period. If unspecified, 0.1 m/s will be used.',
              default=None, type=str)
@click.option('--met-rate', '-m', help='A single number for metabolic rate in met '
              'or a string of a JSON array with numbers that align with the '
              'result-sql reporting period. If unspecified, 1.1 met will be used.',
              default=None, type=str)
@click.option('--clo-value', '-c', help='A single number for clothing level in clo '
              'or a string of a JSON array with numbers that align with the '
              'result-sql reporting period. If unspecified, 0.7 clo will be used.',
              default=None, type=str)
@click.option('--comfort-par', '-cp', help='A PMVParameter string to customize the '
              'assumptions of the PMV model.', default=None, type=str)
@click.option('--result-type', '-t', help='Text to indicate which PMV result data '
              'should be output. Choose from: PMV, PPD, SET, Comfort, Condition.',
              type=str, default='Condition', show_default=True)
@click.option('--output-file', '-f', help='Optional file to output the JSON strings of '
              'the data collections. By default, it will be printed to stdout',
              type=click.File('w'), default='-', show_default=True)
def pmv_by_room(result_sql, air_speed, met_rate, clo_value, comfort_par,
                result_type, output_file):
    """Get data collections for PMV in each room from an EnergyPlus sql.

    \b
    Args:
        result_sql: Path to an SQLite file that was generated by EnergyPlus. This
            file must contain hourly or sub-hourly results for zone comfort variables.
    """
    try:
        # load the energyplus results related to thermal comfort
        sql_obj = SQLiteResult(result_sql)
        air_temps = sql_obj.data_collections_by_output_name(
            'Zone Mean Air Temperature')
        rad_temps = sql_obj.data_collections_by_output_name(
            'Zone Mean Radiant Temperature')
        huimidities = sql_obj.data_collections_by_output_name(
            'Zone Air Relative Humidity')

        # load any of the other data collections if specified
        assert len(air_temps) != 0, \
            'Input result-sql does not contain thermal comfort outputs.'
        base_data = air_temps[0]
        air_speed = load_data(air_speed, base_data, AirSpeed, 'm/s')
        met_rate = load_data(met_rate, base_data, MetabolicRate, 'met')
        clo_value = load_data(clo_value, base_data, ClothingInsulation, 'clo')

        # get aligned data for each room
        align_dict = {a_dat.header.metadata['Zone']: [a_dat] for a_dat in air_temps}
        for h_dat in huimidities:
            align_dict[h_dat.header.metadata['System']].append(h_dat)
        for r_dat in rad_temps:
            align_dict[r_dat.header.metadata['Zone']].append(r_dat)

        # run the collections through the PMV model and output results
        param = load_pmv_par_str(comfort_par)
        pmv_colls = []
        for res in align_dict.values():
            pmv_obj = PMV(res[0], res[1], res[2], air_speed, met_rate, clo_value,
                          comfort_parameter=param)
            if result_type == 'PMV':
                pmv_colls.append(pmv_obj.predicted_mean_vote)
            elif result_type == 'PPD':
                pmv_colls.append(pmv_obj.percentage_people_dissatisfied)
            elif result_type == 'SET':
                pmv_colls.append(pmv_obj.standard_effective_temperature)
            elif result_type == 'Comfort':
                pmv_colls.append(pmv_obj.is_comfortable)
            else:
                pmv_colls.append(pmv_obj.thermal_condition)
        output_file.write(json.dumps([col.to_dict() for col in pmv_colls]))
    except Exception as e:
        _logger.exception('Failed to run PMV model from sql file.\n{}'.format(e))
        sys.exit(1)
    else:
        sys.exit(0)


@sql.command('adaptive-by-room')
@click.argument('result-sql', type=click.Path(
    exists=True, file_okay=True, dir_okay=False, resolve_path=True))
@click.argument('epw-file', type=click.Path(
    exists=True, file_okay=True, dir_okay=False, resolve_path=True))
@click.option('--air-speed', '-v', help='A single number for air speed in m/s or a '
              'string of a JSON array with numbers that align with the result-sql '
              'reporting period. If unspecified, 0.1 m/s will be used.',
              default=None, type=str)
@click.option('--comfort-par', '-cp', help='An AdaptiveParameter string to customize '
              'the assumptions of the Adaptive comfort model.', default=None, type=str)
@click.option('--result-type', '-t', help='Text to indicate which PMV result data '
              'should be output. Choose from: DegreesFromNeutral, Comfort, Condition.',
              type=str, default='Condition', show_default=True)
@click.option('--output-file', '-f', help='Optional file to output the JSON strings of '
              'the data collections. By default, it will be printed to stdout',
              type=click.File('w'), default='-', show_default=True)
def adaptive_by_room(result_sql, epw_file, air_speed, comfort_par,
                     result_type, output_file):
    """Get data collections for Adaptive comfort in each room from an EnergyPlus sql.

    \b
    Args:
        result_sql: Path to an SQLite file that was generated by EnergyPlus. This
            file must contain hourly or sub-hourly results for zone comfort variables.
        epw_file: Path to an .epw file, used to provide prevailing outdoor
            temperature for the adaptive comfort model.
    """
    try:
        # load the energyplus results related to thermal comfort and the EPW object
        epw_obj = EPW(epw_file)
        out_temp = epw_obj.dry_bulb_temperature
        sql_obj = SQLiteResult(result_sql)
        op_temps = sql_obj.data_collections_by_output_name('Zone Operative Temperature')

        # load the air speed data collection if specified
        assert len(op_temps) != 0, \
            'Input result-sql does not contain "Zone Operative Temperature" output.'
        air_speed = load_data(air_speed, op_temps[0], AirSpeed, 'm/s')

        # run the collections through the Adaptive model and output results
        param = load_adaptive_par_str(comfort_par)
        ad_colls = []
        for op_temp in op_temps:
            ad_obj = Adaptive(out_temp, op_temp, air_speed, comfort_parameter=param)
            if result_type == 'DegreesFromNeutral':
                ad_colls.append(ad_obj.degrees_from_neutral)
            elif result_type == 'Comfort':
                ad_colls.append(ad_obj.is_comfortable)
            else:
                ad_colls.append(ad_obj.thermal_condition)
        output_file.write(json.dumps([col.to_dict() for col in ad_colls]))
    except Exception as e:
        _logger.exception('Failed to run Adaptive model from sql file.\n{}'.format(e))
        sys.exit(1)
    else:
        sys.exit(0)
