"""
This module is used to estimate the Herfindahl-Hirschman Index, or HHI, of
chemical compounds. The HHI is a measure of how geographically confined or
dispersed the elements comprising a compound are. A low HHI is desirable
because it means the component elements are geographically dispersed.

Data/strategy from "Data-Driven Review of Thermoelectric Materials:
Performance and Resource Considerations" by Gaultois et al., published
in Chemistry of Materials (2013).
"""

from __future__ import annotations

import os

from monty.design_patterns import singleton

from pymatgen.core import Composition, Element

__author__ = "Anubhav Jain"
__copyright__ = "Copyright 2014, The Materials Project"
__version__ = "0.1"
__maintainer__ = "Anubhav Jain"
__email__ = "ajain@lbl.gov"
__date__ = "Oct 27, 2014"


MODULE_DIR = os.path.dirname(os.path.abspath(__file__))
HHI_CSV_PATH = f"{MODULE_DIR}/hhi_data.csv"


@singleton
class HHIModel:
    """HHI calculator."""

    def __init__(self):
        """Init for HHIModel."""
        self.symbol_hhip_hhir = {}  # symbol->(HHI_production, HHI reserve)

        with open(HHI_CSV_PATH, encoding="utf-8") as file:
            for line in file:
                if line[0] != "#":
                    symbol, hhi_production, hhi_reserve = line.split(",")
                    self.symbol_hhip_hhir[symbol] = float(hhi_production), float(hhi_reserve)

    def _get_hhi_el(self, el_or_symbol):
        """Get the tuple of HHI_production, HHI reserve for a single element only."""
        if isinstance(el_or_symbol, Element):
            el_or_symbol = el_or_symbol.symbol

        return (
            self.symbol_hhip_hhir[el_or_symbol][0],
            self.symbol_hhip_hhir[el_or_symbol][1],
        )

    def get_hhi(self, comp_or_form):
        """Get the reserve and production HHI for a compound.

        Args:
            comp_or_form (CompositionLike): A Composition or String formula

        Returns:
            tuple[float, float]: HHI_production, HHI_reserve
        """
        try:
            if not isinstance(comp_or_form, Composition):
                comp_or_form = Composition(comp_or_form)

            hhi_p = hhi_r = 0

            for e in comp_or_form.elements:
                percent = comp_or_form.get_wt_fraction(e)
                dp, dr = self._get_hhi_el(e)
                hhi_p += dp * percent
                hhi_r += dr * percent
            return hhi_p, hhi_r

        except Exception:
            return None, None

    def get_hhi_production(self, comp_or_form):
        """Get the production HHI for a compound.

        Args:
            comp_or_form (Composition or String): A Composition or String formula

        Returns:
            The HHI production value
        """
        return self.get_hhi(comp_or_form)[0]

    def get_hhi_reserve(self, comp_or_form):
        """Get the reserve HHI for a compound.

        Args:
            comp_or_form (Composition or String): A Composition or String formula

        Returns:
            The HHI reserve value
        """
        return self.get_hhi(comp_or_form)[1]

    @staticmethod
    def get_hhi_designation(hhi):
        """Get a designation for low, medium, high HHI, as specified in "U.S.
        Department of Justice and the Federal Trade Commission, Horizontal
        merger guidelines; 2010.".

        Args:
            hhi (float): HHI value

        Returns:
            The designation as String
        """
        if hhi is None:
            return None

        if 0 <= hhi < 1500:
            return "low"

        if 1500 <= hhi <= 2500:
            return "medium"

        return "high"
