"""
:synopsis: Creates empty Standard geodatabase.
:authors: Riley Baird (OK), Emma Baker (OK)

Implements a tool for an ArcGIS Python Toolbox.
"""


import logging
import random
from pathlib import Path

import arcpy

from ...lib.config_dataclasses import NG911FeatureClass
from ...lib.gdbsession import NG911Session
from ...lib.session import config


_logger = logging.getLogger(__name__)

random_start_phrase = random.choice(['Make it so!', 'Hello World!', 'As the prophecy foretold...', 'Greetings earthlings.', 'All are bases are belong to us.', 'The Jig is up!'])

# required_dataset_name = "NG911"
# optional_dataset_name = "OptionalLayers"
# tool_switch: str = "CREATE_GDB"

error_list = ["--SHOULDN'T BE USED--", "--SHOULDN'T BE USED--", "--SHOULDN'T BE USED--"]


class CreateGDBTool:
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""
        self.label = "1 - Create Standard GDB"
        self.description = "Creates NG911 Standard Geodatabase."
        self.canRunInBackground = False
        self.category = "1 - Prep"

    def getParameterInfo(self):
        """Define parameter definitions"""

        params = []

        output_folder = arcpy.Parameter(
            displayName="Output Folder Location",
            name="output_folder",
            datatype="DEFolder",
            parameterType="Required",
            direction="Input")
        params += [output_folder]

        gdb_name = arcpy.Parameter(
            displayName="Target Geodatabase Name",
            name="gdb_name",
            datatype="GPString",
            parameterType="Required",
            direction="Input")
        params += [gdb_name]

        spatial_ref = arcpy.Parameter(
            displayName="Spatial Reference",
            name="spatial_ref",
            datatype="GPString",
            parameterType="Required",
            direction="Input")
        factory_code_2d = config.gdb_info.spatial_reference_factory_code_2d
        factory_code_3d = config.gdb_info.spatial_reference_factory_code_3d
        spatial_ref.filter.type = "ValueList"
        spatial_ref.filter.list = [f"{arcpy.SpatialReference(factory_code_2d).name} | (2d)", f"{arcpy.SpatialReference(factory_code_3d).name} | (3d)", "--USER SPECIFIED--"]
        spatial_ref.value =  f"{arcpy.SpatialReference(factory_code_2d).name} | (2d)"
        params += [spatial_ref]

        user_spatial_ref = arcpy.Parameter(
            displayName="Spatial Reference",
            name="user_spatial_ref",
            datatype="GPSpatialReference",
            parameterType="Optional",
            direction="Input")
        # user_spatial_ref.value = arcpy.SpatialReference(factory_code_2d)
        params += [user_spatial_ref]

        std_fc_name_value_list = [[config.feature_classes[fc_config_key].name, None, False] for fc_config_key in config.feature_classes]
        disp_parameter_name = f"Standard Feature Classes"
        fc_table = arcpy.Parameter(
            displayName=disp_parameter_name,
            name="fc_table",
            datatype="GPValueTable",
            parameterType="Optional",
            direction="Input")
        fc_table.columns = [['GPString', 'Standard Name', 'ReadOnly'], ['DEFeatureClass', 'Location'], ['GPBoolean', 'Create Blank Feature Class?']]
        fc_table.values = std_fc_name_value_list
        params += [fc_table]

        # OUTPUT
        output_gdb = arcpy.Parameter(
            displayName="Output Geodatabase",
            name="output_gdb",
            datatype="DEWorkspace",
            parameterType="Derived",
            direction="Output")
        params += [output_gdb]

        return params

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

    def updateParameters(self, parameters):
        """Modify the values and properties of parameters before internal
        validation is performed.  This method is called whenever a parameter
        has been changed."""
        gdb_name = parameters[1]
        sr_selected = parameters[2]
        user_sr_selected = parameters[3]
        fc_table = parameters[4]

        # Make sure that gdb_name input value ends with ".gdb"
        if gdb_name.altered and not gdb_name.hasBeenValidated and isinstance(gdb_name.value, str) and gdb_name.value != (correct_value := str(Path(gdb_name.value).with_suffix(".gdb"))):
            gdb_name.value = correct_value

        if sr_selected.altered and not sr_selected.hasBeenValidated:
            if sr_selected.value == "--USER SPECIFIED--":
                user_sr_selected.enabled = True
            else:
                user_sr_selected.enabled = False
        else:
            user_sr_selected.enabled = False

        if fc_table.altered and not fc_table.hasBeenValidated:
            # Fix FC Table
            new_value_list = []
            for idx, value_list in enumerate(fc_table.values):
                std_fc_name = value_list[0]
                fc_obj = value_list[1]
                blank_fc = value_list[2]
                try:
                    fc_path = arcpy.Describe(fc_obj).catalogPath
                except:
                    fc_path = None
                if fc_path:
                    blank_fc = False
                else:
                    blank_fc = blank_fc
                new_value_list.append([std_fc_name, fc_path, blank_fc])
            fc_table.values = new_value_list
        return

    def updateMessages(self, parameters):
        """Modify the messages created by internal validation for each tool
        parameter.  This method is called after internal validation."""
        return

    def execute(self, parameters, messages):
        """The source code of the tool."""
        output_folder_path: str = parameters[0].valueAsText
        gdb_name: str = parameters[1].valueAsText
        sr_from_filter: str = parameters[2].valueAsText
        user_sr = parameters[3].value
        fc_table: list[tuple[NG911FeatureClass, Path | None, bool]] = [
            (
                config.get_feature_class_by_name(standard_fc_name),  # NG911FeatureClass object
                Path(input_fc_value.value) if not input_fc_value.isEmpty else None,  # Path to source FC if provided, else None
                create_blank or False  # Will give False if create_blank is None
            )
            for standard_fc_name, input_fc_value, create_blank
            in parameters[4].values
        ]

        gdb_sr: arcpy.SpatialReference
        if sr_from_filter == "--USER SPECIFIED--":
            gdb_sr = user_sr
        elif sr_from_filter:
            gdb_sr = arcpy.SpatialReference(sr_from_filter.split(" | ")[0])
        else:
            raise ValueError("Invalid argument for spatial reference.")

        with NG911Session.create_standard_gdb(
            output_directory=output_folder_path,
            name=gdb_name,
            spatial_reference=gdb_sr,
            messenger=messages
        ) as session:
            for fc, input_fc_path, create_blank in fc_table:
                if input_fc_path and create_blank:
                    create_blank = False
                    session.messenger.addMessage(f"A source feature class was provided for {fc:n}, but 'Create Blank Feature Class' was also selected. The source feature class will still be used.")
                if input_fc_path or create_blank:
                    session.create_standard_feature_class(fc, False)
                    session.messenger.addMessage(f"Created standard feature class '{fc:n}'.")
                if input_fc_path:
                    try:
                        session.append_to_feature_class(fc, input_fc_path)
                    except Exception as exc:
                        _logger.warning(f"Appending data from '{input_fc_path}' to new standard feature class '{fc:n}' failed.", exc_info=exc)
                    else:
                        session.messenger.addMessage(f"Imported data from '{input_fc_path}' to new standard feature class '{fc:n}'.")

            parameters[-1].value = session.gdb

        # fc_dict = {}
        # for idx, value_list in enumerate(fc_table):  # Loop through once
        #     std_fc_name = value_list[0]
        #     fc_obj = value_list[1]
        #     blank_fc = value_list[2]
        #     try:
        #         fc_path = str(arcpy.Describe(fc_obj).catalogPath)
        #     except:
        #         fc_path = None
        #     if not blank_fc or blank_fc in ["False", "false", "None", "none", "", " ", "#"]:
        #         blank_fc = False
        #     else:
        #         blank_fc = True
        #     if not fc_path and not blank_fc:
        #         continue
        #     fc_dict[std_fc_name] = fc_path
        #
        # arcpy.AddMessage(f"{random_start_phrase}")
        # arcpy.AddMessage(f"\nCreating gdb `{gdb_name}`...")
        # gdb_sr: arcpy.SpatialReference
        # if "--USER SPECIFIED--" != sr_from_filter:
        #     gdb_sr = arcpy.SpatialReference(sr_from_filter.split(" | ")[0])
        # elif user_sr:
        #     gdb_sr = user_sr
        # else:
        #     arcpy.AddWarning(f"...No Spatial Reference provided... Using config...")
        #     gdb_sr = arcpy.SpatialReference(config.gdb_info.spatial_reference_factory_code_2d)
        # gdb_tool_executable = StandardGeodatabaseCreation(output_folder_path, gdb_name)
        # gdb_tool_executable.create_std_gdb(gdb_sr)
        # arcpy.AddMessage(f"...Adding Standard Domains to gdb `{gdb_name}`...")
        # gdb_tool_executable.assign_domain_to_gdb()
        # if fc_dict:
        #     arcpy.AddMessage(f"...Creating and Adding Standard Feature Class(es)...")
        #     for std_fc_name in fc_dict.keys():
        #         user_fc_path = fc_dict[std_fc_name]
        #         fc = config.get_feature_class_by_name(std_fc_name)
        #         std_fc_geom = fc.geometry_type
        #         implement_user_std_fc = StandardFeatureClassCreation(gdb_tool_executable.gdb_path, std_fc_name)
        #         bad_fc_results = implement_user_std_fc.create_blank_fc(std_fc_geom)
        #         if bad_fc_results:
        #             arcpy.AddError(f"{bad_fc_results}")
        #             continue
        #         if user_fc_path:
        #             bad_fc_results = implement_user_std_fc.user_to_std_field_mapping(user_fc_path, None)
        #             if bad_fc_results:
        #                 arcpy.AddWarning(f"{bad_fc_results}")
        #                 continue

        # parameters[-1].value = gdb_tool_executable.gdb_path



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