"""
This module contains objects for.
"""

from __future__ import annotations

# import abipy.core.abinit_units as abu
from functools import cached_property

from monty.string import marquee  # , list_strings

from abipy.abio.robots import Robot

# from abipy.core.kpoints import kpoints_indices
from abipy.core.mixins import AbinitNcFile, Has_ElectronBands, Has_Header, Has_Structure  # , NotebookWriter

# from monty.termcolor import cprint
from abipy.core.structure import Structure

##from abipy.tools import duck
from abipy.electrons.ebands import ElectronBands, RobotWithEbands
from abipy.eph.common import BaseEphReader

# from abipy.tools.numtools import BzRegularGridInterpolator, nparr_to_df
from abipy.tools.typing import PathLike


class WkkpFile(AbinitNcFile, Has_Header, Has_Structure, Has_ElectronBands):
    """
    This file stores the matrix elements of the screened interaction.
    produced by the EPH code, and provides methods to analyze and plot results.

    Usage example:

    .. code-block:: python

        with WkkpFile("out_WKKP.nc") as wkk:
            print(wkk)

    .. rubric:: Inheritance Diagram
    .. inheritance-diagram:: WkkpFile
    """

    @classmethod
    def from_file(cls, filepath: PathLike) -> GstoreFile:
        """Initialize the object from a netcdf file."""
        return cls(filepath)

    def __init__(self, filepath: PathLike):
        """
        Args:.
            filepath: Path to the netcdf file.
        """
        super().__init__(filepath)
        self.r = WkkpReader(filepath)

    @cached_property
    def ebands(self) -> ElectronBands:
        """|ElectronBands| object."""
        return self.r.read_ebands()

    @property
    def structure(self) -> Structure:
        """|Structure| object."""
        return self.ebands.structure

    def close(self) -> None:
        """Close the file."""
        self.r.close()

    @cached_property
    def params(self) -> dict:
        """Dict with the convergence parameters, e.g. ``nbsum``."""
        # od = OrderedDict([
        #    ("symsigma", self.symsigma),
        #    ("nqbz", self.r.nqbz),
        #    ("nqibz", self.r.nqibz),
        # ])
        ## Add EPH parameters.
        # od.update(self.r.common_eph_params)

        od = {}
        return od

    def __str__(self) -> str:
        return self.to_string()

    def to_string(self, verbose: int = 0) -> str:
        """String representation with verbosiy level ``verbose``."""
        lines = []
        app = lines.append

        app(marquee("File Info", mark="="))
        app(self.filestat(as_string=True))
        app("")
        app(self.structure.to_string(verbose=verbose, title="Structure"))

        app("")
        app(self.ebands.to_string(with_structure=False, verbose=verbose, title="Electronic Bands"))
        if verbose > 1:
            app("")
            app(self.hdr.to_string(verbose=verbose, title="Abinit Header"))

        app(f"nsppol: {self.r.nsppol}")

        return "\n".join(lines)


class WkkpReader(BaseEphReader):
    """
    Reads data from file and constructs objects.

    .. rubric:: Inheritance Diagram
    .. inheritance-diagram:: WkkpReader
    """

    def __init__(self, filepath: PathLike):
        """
        Args:.
            filepath: Path to the netcdf file.
        """
        super().__init__(filepath)

        # Read important dimensions.
        # self.nsppol = self.read_dimvalue("number_of_spins")

        # Read important variables.
        # self.completed = self.read_value("gstore_completed")
        # self.done_spin_qbz = self.read_value("gstore_done_qbz_spin")
        # self.with_vk = self.read_value("gstore_with_vk")
        # self.qptopt = self.read_value("gstore_qptopt")
        # self.kptopt = self.read_value("kptopt")
        # self.kzone = self.read_string("gstore_kzone")
        # self.qzone = self.read_string("gstore_qzone")
        # self.kfilter = self.read_string("gstore_kfilter")
        # self.gmode = self.read_string("gstore_gmode")

        # Note conversion Fortran --> C for the isym index.
        # self.brange_spin = self.read_value("gstore_brange_spin")
        # self.brange_spin[:,0] -= 1
        # self.erange_spin = self.read_value("gstore_erange_spin")
        # Total number of k/q points for each spin after filtering (if any)
        # self.glob_spin_nq = self.read_value("gstore_glob_nq_spin")
        # self.glob_nk_spin = self.read_value("gstore_glob_nk_spin")

        # K-points and q-points in the IBZ
        # self.kibz = self.read_value("reduced_coordinates_of_kpoints")
        # self.qibz = self.read_value("gstore_qibz")

        # K-points and q-points in the BZ
        # self.kbz = self.read_value("gstore_kbz")
        # self.qbz = self.read_value("gstore_qbz")
        # self.ngqpt = self.read_value("gstore_ngqpt")

        # Mapping BZ --> IBZ. Note conversion Fortran --> C for the isym index.
        # nctkarr_t("gstore_kbz2ibz", "i", "six, gstore_nkbz"), &
        # nctkarr_t("gstore_qbz2ibz", "i", "six, gstore_nqbz"), &
        self.kbz2ibz = self.read_value("gstore_kbz2ibz")
        self.kbz2ibz[:, 0] -= 1

        self.qbz2ibz = self.read_value("gstore_qbz2ibz")
        self.qbz2ibz[:, 0] -= 1

        # Mapping q/k points in gqk --> BZ. Note conversion Fortran --> C for indexing.
        # nctkarr_t("gstore_qglob2bz", "i", "gstore_max_nq, number_of_spins"), &
        # nctkarr_t("gstore_kglob2bz", "i", "gstore_max_nk, number_of_spins") &
        # self.qglob2bz = self.read_value("gstore_qglob2bz")
        # self.qglob2bz -= 1
        # self.kglob2bz = self.read_value("gstore_kglob2bz")
        # self.kglob2bz -= 1


class WkkpRobot(Robot, RobotWithEbands):
    """
    This robot analyzes the results contained in multiple WKKP.nc files.

    Usage example:

    .. code-block:: python

        robot = WkkpRobot.from_files([
            "t04o_WKKP.nc",
            "t05o_WKKP.nc",
            ])

        robot.neq(verbose=1)

    .. rubric:: Inheritance Diagram
    .. inheritance-diagram:: WkkpRobot
    """

    EXT = "WKKP"

    def yield_figs(self, **kwargs):  # pragma: no cover
        """
        This function *generates* a predefined list of matplotlib figures with minimal input from the user.
        Used in abiview.py to get a quick look at the results.
        """
        # for fig in self.get_ebands_plotter().yield_figs(): yield fig

    # def write_notebook(self, nbpath=None) -> str:
    #    """
    #    Write a jupyter_ notebook to ``nbpath``. If nbpath is None, a temporary file in the current.
    #    working directory is created. Return path to the notebook.
    #    """
    #    nbformat, nbv, nb = self.get_nbformat_nbv_nb(title=None)

    #    args = [(l, f.filepath) for l, f in self.items()]
    #    nb.cells.extend([
    #        #nbv.new_markdown_cell("# This is a markdown cell"),
    #        nbv.new_code_cell("robot = abilab.GstoreRobot(*%s)\nrobot.trim_paths()\nrobot" % str(args)),
    #        #nbv.new_code_cell("ebands_plotter = robot.get_ebands_plotter()"),
    #    ])

    #    # Mixins
    #    #nb.cells.extend(self.get_baserobot_code_cells())
    #    #nb.cells.extend(self.get_ebands_code_cells())

    #    return self._write_nb_nbpath(nb, nbpath)
