#!/user/bin/env python
# -*- coding: utf-8 -*-
"""
Copyright (C) 2024 Galaxy Technologies
Licensed under the Apache License, Version 2.0
"""
import datetime
from pricelib.common.date_handler import CN_CALENDAR, AnnualDays, global_evaluation_date
from pricelib.common.utilities.utility import time_this
from pricelib.common.product_base import OptionBase
from pricelib.pricing_engines.analytic_engines.cashflow_engine import CashFlowEngine

__all__ = ['EnhancedIndexing']


class EnhancedIndexing(OptionBase):
    """指数增强"""

    def __init__(self, excess_return: float, s0: float, margin_lvl=1.,
                 start_date=None, end_date=None, maturity=None, *, engine=None,
                 trade_calendar=CN_CALENDAR, annual_days=AnnualDays.N365, t_step_per_year=243,
                 stoch_process=None, s=None, r=None, q=None, vol=None, engine_method=None):
        """构造函数
        Args:
            excess_return: float，年化的超额收益率
            s0: float，标的初始价格
            margin_lvl: float，保证金比例，默认为1，即无杠杆
            engine: 定价引擎，PricingEngine类，任意，因指数增强定价时，不需要定价引擎参与计算，只需要定价引擎中的标的资产随机过程
        时间参数: 要么输入年化期限，要么输入起始日和到期日；敲出观察日和票息支付日可缺省
            maturity: float，年化期限
            start_date: datetime.date，起始日
            end_date: datetime.date，到期日
            trade_calendar: 交易日历，Calendar类，默认为中国内地交易日历
            annual_days: int，每年的自然日数量
            t_step_per_year: int，每年的交易日数量
        可选参数:
            若未提供引擎的情况下，提供了标的价格、无风险利率、分红/融券率、波动率，
            则默认使用定价引擎 CashFlowEngine
            stoch_process: 随机过程StochProcessBase对象
            s: float，标的价格
            r: float，无风险利率
            q: float，分红/融券率
            vol: float，波动率
        """
        super().__init__()
        self.s0 = s0  # 标的初始价格
        self.trade_calendar = trade_calendar  # 交易日历
        self.annual_days = annual_days
        self.t_step_per_year = t_step_per_year
        assert maturity is not None or (start_date is not None and end_date is not None), "Error: 到期时间或起止时间必须输入一个"
        self.start_date = start_date if start_date is not None else global_evaluation_date()  # 起始时间
        self.end_date = end_date if end_date is not None else (
                self.start_date + datetime.timedelta(days=round(maturity * annual_days.value)))  # 结束时间
        if self.trade_calendar.isholiday(self.end_date):  # 如果到期日不是交易日，向后顺延一个交易日
            self.end_date = self.trade_calendar.advance(self.end_date, datetime.timedelta(days=1))
        if maturity is None:
            self.maturity = (end_date - start_date).days / annual_days.value
        else:
            self.maturity = maturity

        self.excess_return = excess_return
        self.margin_lvl = margin_lvl

        if engine is not None:
            self.set_pricing_engine(engine)
        elif stoch_process is not None:
            default_engine = CashFlowEngine(stoch_process)
            self.set_pricing_engine(default_engine)
        elif s is not None and r is not None and q is not None and vol is not None:
            default_engine = CashFlowEngine(s=s, r=r, q=q, vol=vol)
            self.set_pricing_engine(default_engine)

    def set_pricing_engine(self, engine):
        """设置定价引擎"""
        self.engine = engine

    def __repr__(self):
        """返回产品的描述"""
        return "指数增强"

    @time_this
    def price(self, t: datetime.date = None, spot=None):
        """计算指数增强估值
        Args:
            t: datetime.date，计算指数增强估值的日期
            spot: float/np.ndarray，标的价格
        Returns: 指数增强估值
        """
        calculate_date = global_evaluation_date() if t is None else t
        self.validate_parameters(t=t)
        # 当估值日就是到期日时
        if calculate_date == self.end_date:
            value = self.s0 * (self.margin_lvl + self.maturity * self.excess_return) + (spot - self.s0)
        else:
            tau = (self.end_date - calculate_date).days / self.annual_days  # 计算估值日到到期日的自然日期限
            r = self.engine.process.interest(tau)
            value = (self.s0 * (self.margin_lvl + self.maturity * self.excess_return)
                     + (spot * (1 + r * tau) - self.s0)) * self.engine.process.interest.disc_factor(tau)
        return value

    # def delta(self, t: datetime.date = None, *args, **kwargs):
    #     calculate_date = global_evaluation_date() if t is None else t
    #     tau = (self.end_date - calculate_date).days  # 计算估值日到到期日的自然日期限
    #     r = self.process.interest(tau)
    #     delta = (1 + r * tau)
    #     return delta

    def gamma(self, *args, **kwargs):
        gamma = 0
        return gamma

    def vega(self, *args, **kwargs):
        vega = 0
        return vega

    # def theta(self, t: datetime.date = None, *args, **kwargs):
    #     calculate_date = global_evaluation_date() if t is None else t
    #     theta = self.price() * -self.engine.process.interest(calculate_date)
    #     return theta
    #
    # def rho(self, *args, **kwargs):
    #     rho = 0
    #     return rho
