"""
:synopsis: Add Topology
:authors: Riley Baird (OK), Emma Baker (OK)

"""
from os.path import join
from pathlib import Path

import arcpy

from ...lib.gdbsession import NG911Session
from ...lib.misc import unwrap
from ...lib.session import config
from ...lib.topology import topology_config

_rds = config.gdb_info.required_dataset_name  # "[r]equired [d]ata[s]et"
_rdst = topology_config.required_dataset_topology_name  # "[r]equired [d]ata[s]et [t]opology"
_ods = config.gdb_info.optional_dataset_name  # "[o]ptional [d]ata[s]et"
_odst = topology_config.optional_dataset_topology_name  # "[o]ptional [d]ata[s]et [t]opology"

# ParamDict = dict[str, arcpy.Parameter]
# ParamValueDict = dict[str, GPParameterValue | list[GPParameterValue]]
# ToolValidationMethod = Callable[[Any, list[arcpy.Parameter]], None]
# ToolValidationDictMethod = Callable[[Any, list[arcpy.Parameter]], None]
# ToolExecuteMethod = Callable[[Any, list[arcpy.Parameter], GPMessenger], None]
# ToolExecuteDictsMethod = Callable[[Any, ParamDict, ParamValueDict, GPMessenger], None]
#
# @overload
# def params_as_dict(func: ToolValidationDictMethod) -> ToolValidationMethod: ...
#
# @overload
# def params_as_dict(func: ToolExecuteDictsMethod) -> ToolExecuteMethod: ...
#
# def params_as_dict(func: ToolValidationDictMethod | ToolExecuteDictsMethod) -> ToolValidationMethod | ToolExecuteMethod:
#     arg_count = len(signature(func).parameters.keys())
#     wraps_decorator = wraps(func, tuple(set(WRAPPER_ASSIGNMENTS) - {"__annotations__"}))
#     if arg_count == 2:
#         @wraps_decorator
#         def _inner(self, parameters: list[arcpy.Parameter]):
#             return func(self, params_to_dict(parameters))
#     elif arg_count == 3:
#         @wraps_decorator
#         def _inner(self, parameters: list[arcpy.Parameter], messages: GPMessenger):
#             return func(self, params_to_dict(parameters), messages)
#     else:
#         raise ValueError("Expected function with parameters (self, parameters) or (self, parameters, messages).")
#     return _inner


class AddNG911Topology:
    """
    Class describing an ArcGIS Python Toolbox tool: "Add Topology".
    """
    
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""
        self.label = "Add Topology"
        self.description = ""
        self.category = "3 - Enhancement"
        self.canRunInBackground = False

    def getParameterInfo(self):
        """Define parameter definitions"""
        params = [
            arcpy.Parameter(
                displayName="NG911 Geodatabase",
                name="gdb",
                datatype="DEWorkspace",
                parameterType="Required",
                direction="Input"
            ),
            arcpy.Parameter(
                displayName="Validate",
                name="validate",
                datatype="GPBoolean",
                parameterType="Optional",
                direction="Input",
                enabled=False
            ),
            # OUTPUT
            arcpy.Parameter(
                displayName="Output Required Topology",
                name="output_required_topology",
                datatype="DETopology",
                parameterType="Derived",
                direction="Output"
            ),
            arcpy.Parameter(
                displayName="Output Optional Topology",
                name="output_optional_topology",
                datatype="DETopology",
                parameterType="Derived",
                direction="Output"
            )
        ]
        return params

    def isLicensed(self):
        """Set whether tool is licensed to execute."""
        return True

    # @params_as_dict
    # def updateParameters(self, parameters: dict[str, arcpy.Parameter]):
    def updateParameters(self, parameters: list[arcpy.Parameter]):
        """Modify the values and properties of parameters before internal
        validation is performed.  This method is called whenever a parameter
        has been changed."""
        gdb_p, validate_p = parameters[:2]
        gdb: str
        validate: bool
        gdb, validate = unwrap(parameters[:2])
        try:
            rdst_path_str: str = join(gdb, _rds, _rdst)
            odst_path_str: str = join(gdb, _ods, _odst)
            if gdb_p.altered and arcpy.Exists(gdb):  # (arcpy.Exists(rdst_path_str) or arcpy.Exists(odst_path_str)):
                validate_p.enabled = True
                if not validate_p.altered:
                    validate_p.value = True
            else:
                raise
        except:
            validate_p.enabled = False
            validate_p.value = None

    def updateMessages(self, parameters: list[arcpy.Parameter]):
        """Modify the messages created by internal validation for each tool
        parameter.  This method is called after internal validation."""
        gdb: str
        validate: bool
        gdb, validate = unwrap(parameters[:2])
        already_exists_messages: list[str] = []
        if gdb and Path(gdb).exists():
            if arcpy.Exists(join(gdb, _rds, _rdst)):
                already_exists_messages.append(f"Topology '{_rds}/{_rdst}' already exists and will be deleted.")
            if arcpy.Exists(join(gdb, _ods, _odst)):
                already_exists_messages.append(f"Topology '{_ods}/{_odst}' already exists and will be deleted.")
        if already_exists_messages:
            parameters[0].setWarningMessage(" ".join(already_exists_messages))
        else:
            parameters[0].clearMessage()

    def execute(self, parameters, messages):
        """The source code of the tool."""
        gdb: str
        validate: bool
        gdb, validate = unwrap(parameters[:2])
        with NG911Session(gdb, False, messenger=messages) as session:
            modified_rdst, modified_odst = session.add_and_configure_topologies(True)
            if validate:
                session.validate_topologies()
            parameters[-2].value = session.str_path_to(_rdst) if modified_rdst else None
            parameters[-1].value = session.str_path_to(_odst) if modified_odst else None


if __name__ == "__main__":
    raise Exception("This module is a dependency of an ArcGIS Python Toolbox and should not be executed directly.")