#!/user/bin/env python
# -*- coding: utf-8 -*-
"""
Copyright (C) 2024 Galaxy Technologies
Licensed under the Apache License, Version 2.0
"""
import numpy as np
from pricelib.common.pricing_engine_base import QuadEngine
from pricelib.common.date_handler import global_evaluation_date


class QuadPhoenixEngine(QuadEngine):
    """Phoenix/DCN/FCN 数值积分定价引擎
            较雪球式AutoCallable，增加派息价格，少了敲出和红利票息
            每个派息（敲出）观察日，如果价格高于派息价格，派固定利息，如果发生敲出，合约提前结束；
            发生敲入后，派息方式不变，到期如果未敲出，结构为看跌空头或熊市价差空头
        FCN(Fixed Coupon Note, 固定票息票据)/DCN(Dynamic Coupon Note, 动态票息票据)/Phoenix凤凰票据
            FCN：无派息价格（派息价格为0），每月固定派息；到期日观察是否敲入
            DCN：有派息价格，每个观察日如果价格高于派息价格，派固定利息；到期日观察是否敲入
            Phoenix：有派息价格，每个观察日如果价格高于派息价格，派固定利息；每日观察是否敲入
    """

    # pylint: disable=too-many-locals
    def calc_present_value(self, prod, t=None, spot=None, calc_greeks=False, s_step=0.001):
        """计算现值
        Args:
            prod: Product产品对象
            t: datetime.date，估值日; 如果是None，则使用全局估值日globalEvaluationDate
            spot: float，估值日标的价格，如果是None，则使用随机过程的当前价格
            calc_greeks: bool，是否计算delta和gamma，默认为False，即只计算理论估值
            s_step: float，价格网格步长（百分比）
        Returns:
            若只计算pv，返回float，现值 pv
            若计算pv、delta和gamma，返回np.ndarray [down_price, pv, up_price] ，其中 down_price 和 up_price 是 s±Δs 的理论估值
        """
        self.prod = prod
        calculate_date = global_evaluation_date() if t is None else t
        if spot is None:
            spot = self.process.spot()

        if calc_greeks:  # 计算理论估值、delta和gamma
            value_portfolio = np.zeros(3)
        else:  # 只计算理论估值
            value_portfolio = 0

        # 截取子产品（选取end_date大于calculate_date的产品）
        sub_products = [sub_product for sub_product in prod.sub_products if sub_product.end_date >= calculate_date]
        # 子产品定价
        for i, sub_product in enumerate(sub_products):
            sub_product.engine.quad_method = self.quad_method
            sub_product.engine.n_points = self.n_points
            sub_value = sub_product.engine.calc_present_value(prod=sub_product, t=t, spot=spot,
                                                              calc_greeks=calc_greeks, s_step=s_step)
            # logging.info(f"{i}, {sub_product.__class__.__name__}, {sub_value}")
            value_portfolio += sub_value

        return value_portfolio
