"""Derras, Bard and Cotton (2014, :cite:`derras14`) model."""

import json
import os

import numpy as np

from . import model

__author__ = "Albert Kottke"


class DerrasBardCotton2014(model.GroundMotionModel):
    """Derras, Bard and Cotton (2014, :cite:`derras14`) model.

    Parameters
    ----------
    scenario : :class:`pygmm.model.Scenario`
        earthquake scenario

    """

    NAME = "Derras, Bard & Cotton (2014)"
    ABBREV = "DBC13"

    # Load the coefficients for the model
    COEFF = json.load(
        open(os.path.join(os.path.dirname(__file__), "data", "derras_bard_cotton_2014.json"))
    )
    GRAVITY = 9.80665
    PERIODS = np.array(COEFF["period"])

    INDICES_PSA = np.arange(2, 64)
    INDEX_PGA = 1
    INDEX_PGV = 0
    PARAMS = [
        model.NumericParameter("dist_jb", True, 5, 200),
        model.NumericParameter("mag", True, 4, 7),
        model.NumericParameter("v_s30", True, 200, 800),
        model.NumericParameter("depth_hyp", True, 0, 25),
        model.CategoricalParameter("mechanism", True, ["SS", "NS", "RS"]),
    ]

    def __init__(self, scenario: model.Scenario):
        """Initialize the model."""
        super().__init__(scenario)
        c = self.COEFF
        # Values modified during the calculation
        s = dict(self._scenario)

        for k in ["v_s30", "dist_jb"]:
            s["log10_" + k] = np.log10(s[k])
        # Translate to mechanism integer
        s["mechanism"] = dict(NS=1, RS=3, SS=4)[s["mechanism"]]

        # Create the normalized parameter matrix
        keys = ["log10_dist_jb", "mag", "log10_v_s30", "depth_hyp", "mechanism"]
        values = np.array([s[k] for k in keys])
        limits = np.rec.array([c["min_max"][k] for k in keys], names="min,max")
        p_n = np.array(2 * (values - limits["min"]) / (limits["max"] - limits["min"]) - 1).T

        # Compute the normalized response
        b_1 = np.array(c["b_1"]).T
        b_2 = np.array(c["b_2"]).T
        w_1 = np.array(c["w_1"])
        w_2 = np.array(c["w_2"])

        log10_resp_n = b_2 + w_2 @ np.tanh(b_1 + w_1 @ p_n)

        # Convert from normalized values
        log10_resp_limits = np.rec.array(c["min_max"]["log10_resp"], names="min,max")
        log10_resp = (
            0.5 * (log10_resp_n + 1) * (log10_resp_limits["max"] - log10_resp_limits["min"])
            + log10_resp_limits["min"]
        )
        # Convert from m/sec and m/sec² into cm/sec and g
        scale = np.log10(np.r_[0.01, self.GRAVITY * np.ones(self.PERIODS.size - 1)])

        self._ln_resp = np.log(10 ** (log10_resp - scale))
        self._ln_std = np.log(10 ** np.array(c["log10_std"]["total"]))
