# -*- coding: utf-8 -*-

from typing import Dict, Union

from pyesl.aggs import AggsBase
from pyesl.query import QueryBase


class ScriptField(AggsBase):
    """
    **New field that generated by original field of the same doc**

    :param fields: script使用的字段集合,{"expr_name1", "field_name1"}
    :type fields: Dict[str, str]
    :param expr: 生成新Field的表达式
    :type expr: str
    :param alias: 生成新Field的别名
    :type alias: str
    :param field_format: script中使用field的script代码模版,default: doc['field.{field}'].value
    :type field_format: str
    :param expr_params: 生成ScriptField字段的参数,例如一些乘数、除数等
    :type expr_params: Union[Dict[str, Union[str, float]], None]
    :param param_format: script中使用param的script代码模版,default: params.{param}
    :type param_format: str

    - For case::

        1. sql like: select a+b as c
        3. aql like: (ms_gb_distinct.count + ms_gb_distinct.value) + 2 / 3

    """

    _BODY_TEMPLATE = {
        "alias_1": {
            "script": {
                "source": "doc['field.{field}'].value + doc['field.{field}'].value + params.{param} / params.{param}",
                "params": {
                    "params_1": 2,
                    "params_2": 3
                }
            }
        }
    }

    def __init__(
            self, fields: Dict[str, str], expr: str, alias: Union[str, None] = None,
            field_format: str = "doc['field.{field}'].value",
            expr_params: Union[Dict[str, float], None] = None, param_format: str = "params.{param}"
    ):
        _name = alias or 'cal_{}'.format('#'.join(fields))
        self._fields_formatted = {}
        for key, field_name in fields.items():
            self._fields_formatted[key] = field_format.format(field=field_name)
        if expr_params:
            id_gap = 0
            self._expr_params_formatted = {}
            self._expr_params_value = {}
            for idx, org_param_name in enumerate(sorted(expr_params.keys()), 1):
                param_value = expr_params[org_param_name]
                # 统一化处理，避免过多的script语句产生
                new_param_name = 'param{id}'.format(id=idx + id_gap)
                while new_param_name in self._fields_formatted or new_param_name in self._expr_params_value:
                    id_gap += 1
                    new_param_name = 'param{id}'.format(id=idx + id_gap)
                self._expr_params_formatted[org_param_name] = param_format.format(param=new_param_name)
                self._expr_params_value[new_param_name] = param_value
            self._expr_formatted = expr.format(**self._fields_formatted, **self._expr_params_formatted)
            _body = {
                _name: {
                    'script': {
                        'source': self._expr_formatted,
                        'params': self._expr_params_value
                    }
                }
            }
        else:
            self._expr_formatted = expr.format(**self._fields_formatted)
            _body = {
                _name: {
                    'script': {
                        'source': self._expr_formatted
                    }
                }
            }
        super().__init__(_body, _name)


class ScriptFields(AggsBase):
    """
    **Script field of the data point**

    :param script_field: 字段之间四则运算的字段列表
    :type script_field: ScriptField
    """
    _BODY_TEMPLATE = {
        "script_fields": {
            "alias_1": {
                "script": {
                    "source": "doc['field.{field}'].value + doc['field.{field}'].value"
                }
            },
            "alias_2": {
                "script": {
                    "source": "doc['field.{field}'].value + doc['field.{field}'].value * params.{param}",
                    "params": {
                        "params_1": 1
                    }
                }
            }
        }
    }

    def __init__(self, *script_field: ScriptField):
        _body = {
            "script_fields": {}
        }
        _result_path = []
        for _f in script_field:
            _body['script_fields'][_f.name] = _f.body[_f.name]
            _result_path.append(_f.name)
        super().__init__(_body, 'sf_{}'.format('#'.join(_result_path)))
        self._result_path = _result_path


class Field(object):
    def __init__(self, name: str, ):
        self._name = name

    @property
    def name(self):
        return self._name


class SourceFields(QueryBase):
    """
    **Original field of the data point**

    :param fields: 查询字段列表
    :type fields: Field

    """
    _BODY_TEMPLATE = {
        "_source": {
            "includes": ["tag", "field", "ts", "metric"]
        }
    }

    def __init__(self, *fields: Field):
        _body = {
            "_source": {
                "includes": [_f.name for _f in fields]
            }
        }
        super().__init__(_body)


class Fields(object):
    def __init__(self, source_fields: SourceFields = None, script_fields: ScriptFields = None):
        self._source_fields = source_fields
        self._script_fields = script_fields

    @property
    def source_fields(self) -> SourceFields:
        return self._source_fields

    @property
    def script_fields(self) -> ScriptFields:
        return self._script_fields
