import sys

sys.path.insert(0, r".\src")
from warnings import warn

import powfacpy


class PFCgmesInterface(powfacpy.PFActiveProject):
    """Interface for CGMES integration in PowerFactory."""

    def __init__(self, app):
        warn(
            f"{self.__class__.__name__} will be deprecated. Please use the class 'CGMES' from 'applications/model_exchange' instead",
            DeprecationWarning,
            stacklevel=2,
        )
        super().__init__(app)
        self.ARCHIVE_NAME = "cgmes_archive"
        self.ARCHIVE_FOLDER_NAME = "cgmes_archive_folder"
        self.FILE_TO_ARCHIVE_TOOL_NAME = "cgmes_file_to_archive"
        self.ARCHIVE_TO_FILE_TOOL_NAME = "cgmes_archive_to_file"
        self.ARCHIVE_TO_GRID_TOOL_NAME = "cgmes_archive_to_grid"
        self.GRID_TO_ARCHIVE_TOOL_NAME = "cgmes_grid_to_archive"
        self.EXPORTED_ZIP_NAME = "cgmes_profiles"
        self.CGMES_VERSION = "CGMES 3.0.0"
        self._ALL_PROFILES = "eq tp ssh sc sv dy dl gl"

    # Import functions

    def _create_cim_to_grid_tool(self):
        """Returns the CIM to Grid tool object .ComCimtogrid."""
        cim_to_grid_tool = self.create_in_folder(
            self.ARCHIVE_TO_GRID_TOOL_NAME + ".ComCimtogrid",
            self.app.GetActiveStudyCase(),
            use_existing=True,
        )
        return cim_to_grid_tool

    def _convert_file_to_archive(self, file_path: str, name: str):
        """Convert a .zip CGMES file to a PowerFactory .CimArchive object. Returns the .CimArchive object."""
        file_to_archive_tool = self.create_in_folder(
            self.FILE_TO_ARCHIVE_TOOL_NAME + ".ComCimdbimp",
            self.app.GetActiveStudyCase(),
            use_existing=True,
        )
        file_to_archive_tool.iopt_target = 2
        archive = self._create_archive(name="_".join([self.ARCHIVE_NAME, name]))
        file_to_archive_tool.targetPath = archive
        file_to_archive_tool.fileName = file_path
        file_to_archive_tool.Execute()
        return archive

    def _convert_archive_to_grid(self, cim_archive):
        """Convert a PowerFactory .CimArchive to a grid. Returns None."""
        cim_to_grid_tool = self._create_cim_to_grid_tool()
        cim_to_grid_tool.sourcePath = cim_archive
        cim_to_grid_tool.dependencies = None
        cim_to_grid_tool.partial = 0
        # cim_to_grid_tool.pGrid = [grid] # TODO find out if grid has to be given
        cim_to_grid_tool.Execute()
        return None

    def cgmes_import(self, input_path: str):
        """Converts CGMES .zip files to a PowerFactory grid.

        Args:
            input_path (str): Path to the CGMES .zip archive, containing xml profiles.

        Returns:
            None
        """
        archive = self._convert_file_to_archive(input_path, "imported")
        self._convert_archive_to_grid(archive)
        return None

    def update_profiles(self, update_file_path: str, base_archive):
        """Includes new SSH (and DL) profiles into an already imported grid.

        Args:
            update_file_path (str): Path to the CGMES .zip archive, containing profiles for updating (SSH and optionally DL).
            base_archive (PowerFactory.DataObject|str) Base .CimArchive which the already imported grid has been created from.

        Returns:
            None
        """
        base_archive = self._handle_single_pf_object_or_path_input(base_archive)
        update_profiles_archive = self._convert_file_to_archive(
            update_file_path, "imported_profiles_for_update"
        )
        cim_to_grid_tool = self._create_cim_to_grid_tool()
        cim_to_grid_tool.sourcePath = update_profiles_archive
        cim_to_grid_tool.dependencies = base_archive
        cim_to_grid_tool.partial = 1
        profiles_in_update_file = [
            file.loc_name.split("_")[-2]
            for file in update_profiles_archive.GetContents()
        ]
        self._set_profiles_of_cim_tool(cim_to_grid_tool, self._ALL_PROFILES, False)
        self._set_profiles_of_cim_tool(
            cim_to_grid_tool, " ".join(profiles_in_update_file), True
        )
        # cim_to_grid_tool.pGrid = [grid] # TODO find out if grid has to be given
        cim_to_grid_tool.Execute()
        return None

    # Export functions

    def _create_grid_to_cim_tool(self):
        """Returns the Grid to CIM tool object .ComGridtocim."""
        grid_to_cim_tool = self.create_in_folder(
            self.GRID_TO_ARCHIVE_TOOL_NAME + ".ComGridtocim",
            self.app.GetActiveStudyCase(),
            use_existing=True,
        )
        grid_to_cim_tool.cAuthority = ["Authority1"]  # TODO this probably isn't general
        grid_to_cim_tool.cSelected = [
            1
        ]  # TODO this probably isn't general (should all grids be selected? or actually only the first one?) --> get project with >1 grid and get to run properly
        grid_to_cim_tool.version = self.CGMES_VERSION
        return grid_to_cim_tool

    def _get_archive_folder(self):
        """Get or create the folder for PowerFactory .CimArchive objects. Returns the folder."""
        archive_folder = self.create_in_folder(
            self.ARCHIVE_FOLDER_NAME + ".IntPrjfolder",
            self.app.GetActiveProject(),
            use_existing=True,
            overwrite=False,
        )
        archive_folder.iopt_typ = "cim"
        return archive_folder

    def _create_archive(self, name):
        """Create a PowerFactory .CimArchive object. Returns the .CimArchive object."""
        archive_folder = self._get_archive_folder()
        archive = self.create_in_folder(
            name + ".CimArchive", archive_folder, use_existing=False, overwrite=True
        )
        return archive

    def _set_profiles_of_cim_tool(self, cim_tool, profiles: str, state: bool):
        """Sets the profiles of PowerFactory .ComCimtogrid or .ComGridtocim tools listet in profiles to state.
        Args:
            cim_tool (str): .ComCimtogrid or .ComGridtocim tool.
            profiles (str): String of CGMES profiles to be set in the tool, separeted by single spaces (e.g. 'ssh dl').
            state (bool): State to set the selected prfiles to (True=checked, False=unchecked).
        Returns:
            None
        """
        cim_tool = self._handle_single_pf_object_or_path_input(cim_tool)
        for profile in profiles.split(" "):
            cim_tool.SetAttribute("convert" + profile.upper(), state)
        return None

    def _convert_grid_to_archive(self, selected_profiles: str = "all"):
        """Convert a PowerFactory grid to a .CimArchive. Returns the archive.
        Args:
            selected_profiles (str): String with CGMES profiles to be generated, separeted by single spaces (e.g. 'ssh dl', 'tp'). 'all' selects all profiles.
        Returns:
            None
        """
        grid_to_cim_tool = self._create_grid_to_cim_tool()

        if selected_profiles == "all":
            grid_to_cim_tool.partial = 0  # convert all profiles
        else:
            grid_to_cim_tool.partial = 1  # convert selected profiles
            self._set_profiles_of_cim_tool(grid_to_cim_tool, self._ALL_PROFILES, False)
            self._set_profiles_of_cim_tool(grid_to_cim_tool, selected_profiles, True)

        grid_to_cim_tool.iopt_target = 1  # existing archive
        archive = self._create_archive(
            name="_".join(
                [self.ARCHIVE_NAME, "exported", selected_profiles.replace(" ", "_")]
            )
        )
        grid_to_cim_tool.targetPath = archive
        grid_to_cim_tool.Execute()
        return archive

    def _convert_archive_to_file(self, archive, output_path: str, as_zip: bool = True):
        """Convert a PowerFactory .CimArchive object to a file. Returns None.
        Args:
            archive (PowerFactory .CimArchive object): archive to be converted and saved as a file.
            output_path (str): Path to desired output folder (without file name).
            as_zip (bool): save as .zip file if as_zip, else save as .xml files.

        Returns:
            None
        """
        archive = self._handle_single_pf_object_or_path_input(archive)
        cim_export_tool = self.create_in_folder(
            self.ARCHIVE_TO_FILE_TOOL_NAME + ".ComCimdbexp",
            self.app.GetActiveStudyCase(),
            use_existing=True,
        )
        cim_export_tool.targetFolder = [output_path]
        if as_zip:
            cim_export_tool.zipModels = 0
            cim_export_tool.archiveName = [
                self.EXPORTED_ZIP_NAME,
            ]
        else:
            cim_export_tool.zipModels = 2
        cim_export_tool.sourcePath = archive
        cim_export_tool.Execute()
        return None

    def cgmes_export(
        self, output_path: str, selected_profiles: str = "all", as_zip: bool = True
    ):
        """Exports selected CGMES profiles of active grid.
        Args:
            output_path (str): Path to desired output folder (without file name).
            selected_profiles (str): String with CGMES profiles to be exported, separeted by single spaces (e.g. 'ssh dl', 'tp'). 'all' selects all profiles.
            as_zip (bool): save as .zip file if as_zip, else save as .xml files.

        Returns:
            None
        """
        archive = self._convert_grid_to_archive(selected_profiles=selected_profiles)
        self._convert_archive_to_file(archive, output_path, as_zip=as_zip)
        return None
