#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from utils.input_output import load_yaml
from utils.exceptions import StyleError
from utils.vars import PROPHANE_DIR
import glob
import os
import pandas as pd


class Style(object):
    def __init__(self, yaml):
        self.yaml = yaml
        self._config = self._load_yaml()

    def __setitem__(self, key, item):
        self._config[key] = item

    def __getitem__(self, key):
        try:
            return self._config[key]
        except KeyError:
            raise KeyError(f"'{key}' not found in style '{self.yaml}'")

    def __repr__(self):
        return repr(self._config)

    def __len__(self):
        return len(self._config)

    def __delitem__(self, key):
        del self._config[key]

    def clear(self):
        return self._config.clear()

    def copy(self):
        return self._config.copy()

    def has_key(self, k):
        return k in self._config

    def update(self, *args, **kwargs):
        return self._config.update(*args, **kwargs)

    def keys(self):
        return self._config.keys()

    def values(self):
        return self._config.values()

    def items(self):
        return self._config.items()

    def pop(self, *args):
        return self._config.pop(*args)

    def __contains__(self, item):
        return item in self._config

    def __iter__(self):
        return iter(self._config)

    @staticmethod
    def is_style_yaml(yaml):
        required_keys = ['style', 'program', 'version', 'comment']
        yaml_dict = load_yaml(yaml)
        if type(yaml_dict) is not dict:
            return False
        if all(key in yaml_dict for key in required_keys):
            return True
        else:
            return False

    def _load_yaml(self):
        if self.is_style_yaml(self.yaml):
            return load_yaml(self.yaml)
        else:
            raise StyleError(f"Not a valid style yaml: {self.yaml}")

    def get_program(self):
        return self._config['program'].__str__()

    def get_version(self):
        return self._config['version'].__str__()

    def get_comment(self):
        return self._config['comment'].__str__()

    def get_yaml(self):
        return self.yaml


class StyleAccessor(object):
    def __init__(self):
        self._style_path = os.path.join(PROPHANE_DIR, "styles")
        self._style_yamls = self._get_style_yamls()
        self._df_style_infos = self._get_style_infos()

    def _get_style_yamls(self):
        style_yamls = [f for f in glob.glob(self._style_path + "/*.yaml") if Style.is_style_yaml(f)]
        if not style_yamls:
            raise ValueError('No valid styles were found in \n\t{}'.format(self._style_path))
        return style_yamls

    def _get_style_infos(self):
        df = pd.DataFrame()
        for f in self._style_yamls:
            s = pd.Series(dtype="object")
            style = Style(f)
            s['source'] = style.get_program()
            s['version'] = style.get_version()
            s['comment'] = style.get_comment()
            s['report_style'] = style.get_yaml()
            df = df.append(s, ignore_index=True)
        return df

    def get_style_yaml(self, source, version):
        df = self._df_style_infos
        df = df[df['source'] == source]
        yaml = df[df['version'] == version]['report_style'].values[0]
        return yaml

    def print_summary(self):
        print('\n')
        print('Styles available in "{}":\n'.format(self._style_path))
        df = self._df_style_infos.sort_values(by=['source', 'version'])
        df['report_style'] = df['report_style'].apply(lambda x: os.path.relpath(os.path.abspath(x), self._style_path))
        with pd.option_context('display.max_colwidth', -1):
            print(df[['source', 'version', 'report_style']].to_string(index=False, justify='left'))


def print_available_input_file_styles():
    styleaccessor = StyleAccessor()
    styleaccessor.print_summary()
