#!/usr/bin/env python
# -*- coding: utf-8 -*-
# time: 2023/11/21 13:33
# file: validate.py
# author: David
# company: shenyang JY
import numpy as np
import pandas as pd
from cache.data_cleaning import key_field_row_cleaning
from data_process import DataProcess
from cache.limited_power import LimitPower


class ValidationError(Exception):
    def __init__(self, message):
        self.msg = message


class Validation(object):
    def __init__(self, log, args):
        self.logger = log
        self.args = args
        self.opt = args.parse_args_and_yaml()
        self.status = 1
        self.process = DataProcess(log, args)
        self.lp = LimitPower(log, args, None)

    def validate_nwp(self, nwp):
        # 0. 关键字段是否缺失
        nwp_cs = [x for x in nwp.columns.to_list() if x in self.opt.nwp_columns]
        if 'C_TIME' in nwp_cs:
            nwp_cs.pop(nwp_cs.index('C_TIME'))
        nwp_filter = key_field_row_cleaning(nwp, nwp_cs, self.logger)
        if len(nwp_filter) < 8:
            self.status = 2
            raise ValidationError("NWP数据缺失")
        nwp_filter['C_TIME'] = pd.to_datetime(nwp_filter['C_TIME'])
        return nwp_filter

    def validate_his_data(self, history_rp, env, history_dq):
        if len(history_rp) <= 1 and len(env) <= 1:
            self.status = 3
            raise ValidationError("鉴权失败-历史数据时刻不满足USTA_HISTORY个数")
        if len(history_dq) < self.opt.Model["his_points"]:
            self.status = 2
            raise ValidationError("history_dq缺失")
        his = pd.merge(history_rp, history_dq, on='C_TIME')
        his = pd.merge(env, his, on='C_TIME')
        if self.opt.usable_power['clean_power_which'] in range(1, 3):
            his_clean = key_field_row_cleaning(his, [self.opt.usable_power['env']], self.logger)
        else:
            his_clean = his
        his_clean = his_clean.replace(-99, np.nan)
        points = self.opt.Model['his_points']
        if len(his_clean) < points * 0.5:
            self.status = 2
            raise ValidationError("历史数据缺失，实际长度：{}".format(len(his_clean)))
        elif len(his_clean) < self.opt.Model["his_points"] or his_clean.isnull().any().any():
            his_clean.drop(columns=['C_FP_VALUE'], inplace=True)
            his = pd.merge(history_dq, his_clean, on='C_TIME', how='left')
            his.set_index('C_TIME', inplace=True)
            his = his.interpolate(method='linear')
            his = his.fillna(method='ffill')
            his = his.fillna(method='bfill')
            his.reset_index(drop=False, inplace=True)
            his['LIMIT_STATUS'] = np.where((his['LIMIT_STATUS'] != 0) & (his['LIMIT_STATUS'] != 1), 1, his['LIMIT_STATUS'])
            return his
        else:
            return his_clean

    def validate_authentic(self, nwp, his):
        # 验证当前天气是否经过鉴权，第一个点一定要是当天的
        predict_dt = nwp.iloc[0, :]["C_TIME"]
        history_dt = his.iloc[-1, :]["C_TIME"]
        if predict_dt - history_dt > pd.Timedelta(hours=4):
            self.status = 3
            raise ValidationError("鉴权失败-环境数据结束时间早于预测开始时间4小时")

    def validate_power(self, his):
        history_rp_env = his.copy()
        new_rp = []
        for index, row in history_rp_env.iterrows():
            zfs = row[self.opt.usable_power["env"]]
            rp = row['C_REAL_VALUE']
            able_rp = row['C_ABLE_VALUE']
            status = row['LIMIT_STATUS']
            # 以下三种情况用可用功率替代：
            # 1. api_able_power可用功率参数置为True
            # 2. 取消模型融合，解析接口数据填充
            # 3. 用样板机法或单独信号法清洗限电
            if self.opt.usable_power['api_able_power'] is True or self.opt.Model['fusion'] is False or self.opt.usable_power['clean_power_which'] not in range(1, 3):
                new_rp.append(able_rp)
            # 否则用测光法和限电信号联合判断，任意一种限电就执行
            elif not self.lp.filter_unlimited_power(zfs, rp, self.opt.usable_power['k'], self.opt.usable_power['bias']) or status:  # 任意判断限电
                new_rp.append(able_rp)
            else:
                new_rp.append(rp)  # 全部为不限电
        history_rp_env["NEW_RP"] = new_rp
        return history_rp_env[['C_TIME', 'NEW_RP']]



