"""
Package containing the logic and tools used by the Oklahoma Next-Generation
9-1-1 GIS Toolkit for ArcGIS Pro.

Package initialization sets up logging and patches a few methods in the
``arcgis`` package.

A log file is written to ``../ng911ok.log``.

See :func:`__patch` for details on method patching.
"""
__version__ = "3.2.6"

import datetime
import logging
import sys
from inspect import getfullargspec
from pathlib import Path
from typing import Final

import arcpy

# noinspection PyProtectedMember
import arcgis.features.geo._array  # Used for patching
import arcgis.geometry  # Used for patching
import pandas.core.arrays.base  # Used for patching

__logger = logging.getLogger(__name__)
try:
    __logging_file_path = Path(__file__).parent.parent / "ng911ok.log"
    __log_handler = logging.FileHandler(filename=__logging_file_path, mode="a", encoding="utf-8")
    # logging.basicConfig(filename=__logging_file_path, encoding="utf-8", level=logging.DEBUG, format=__log_format)
except:
    # logging.basicConfig(stream=sys.stdout, level=logging.DEBUG, format=__log_format)
    __log_handler = logging.StreamHandler(stream=sys.stdout)
__logger.setLevel(logging.DEBUG)
__log_handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s: %(name)s/%(funcName)s - %(message)s"))
__logger.addHandler(__log_handler)

# Log version, time, and ArcGIS installation info for diagnostics
__arc_install_info = arcpy.GetInstallInfo()
__logger.info(
    "\n"
    "┌─────────────────┐\n"
    "│ Loading ng911ok │\n"
    "├─────────────────┘\n"
    f"├─ Time: {datetime.datetime.now().astimezone().strftime('%Y-%m-%d %H:%M:%S %z')}\n"
    f"├─ ng911ok: {__version__}\n"
    f"├─ Product: {arcpy.version.data['product_full']}\n"
    f"├─ License: {__arc_install_info['LicenseLevel']} ({__arc_install_info['LicenseType']})\n"
    f"├─ ArcObjects: {arcpy.version.arcobjects}\n"
    f"├─ arcgisscripting: {arcpy.version.arcgisscripting}\n"
    f"└─ arcgis: {arcgis.__version__}"
)

# noinspection PyProtectedMember
def __patch() -> None:
    """
    Patches, as necessary, a few functions in this package's dependencies.

    .. list-table::
       :widths: auto

       * - ``arcgis.features.geo._array.GeoArray._from_factorized()``
         - Adds an argument (``original``) missing from the signature and
           defaults it to ``None``
       * - ``arcgis.geometry._types.Polyline.__getitem__()``
         - When key ``paths`` is requested from a ``Polyline`` that has no
           ``paths`` key, returns ``curvePaths`` instead
       * - ``arcgis.geometry._types.Polygon.__getitem__()``
         - When key ``rings`` is requested from a ``Polygon`` that has no
           ``rings`` key, returns ``curveRings`` instead
    """
    # Patch arcgis.features.geo._array.GeoArray._from_factorized (if needed)
    try:
        extensionarray_from_factorized_method_args = getfullargspec(pandas.core.arrays.base.ExtensionArray._from_factorized).args
        geoarray_from_factorized_method_args = getfullargspec(arcgis.features.geo._array.GeoArray._from_factorized).args
        if len(extensionarray_from_factorized_method_args) > len(geoarray_from_factorized_method_args):
            # Patch GeoArray._from_factorized() because, as implemented in package
            # ``arcgis`` v2.3.0, GeoArray's method does not accept the (unused)
            # argument ``original`` that pandas passes to it
            # noinspection PyUnusedLocal
            def _patched_from_factorized(cls, values, original=None):
                return cls(values)

            arcgis.features.geo._array.GeoArray._from_factorized = classmethod(_patched_from_factorized)
    except Exception as exc:
        __logger.error("Failed checking/patching arcgis.features.geo._array.GeoArray._from_factorized.", exc_info=exc)
    else:
        __logger.debug("Patched arcgis.features.geo._array.GeoArray._from_factorized.")


    # Patch arcgis.geometry.Polyline.__getitem__ to handle geometry with curves
    try:
        if getattr(arcgis.geometry.Polyline.__getitem__, "__name__", None) != "_patched_polyline_getitem__":
            original_polyline_getitem = arcgis.geometry.Polyline.__getitem__
            def _patched_polyline_getitem__(self, k):
                if k == "paths" and "paths" not in self:
                    return original_polyline_getitem(self, "curvePaths")
                else:
                    return original_polyline_getitem(self, k)
            arcgis.geometry.Polyline.__getitem__ = _patched_polyline_getitem__
    except Exception as exc:
        __logger.error("Failed checking/patching arcgis.geometry.Polyline.__getitem__.", exc_info=exc)
    else:
        __logger.debug("Patched arcgis.geometry.Polyline.__getitem__.")

    # Patch arcgis.geometry.Polygon.__getitem__ to handle geometry with curves
    try:
        if getattr(arcgis.geometry.Polygon.__getitem__, "__name__", None) != "_patched_polygon_getitem__":
            original_polygon_getitem = arcgis.geometry.Polygon.__getitem__
            def _patched_polygon_getitem__(self, k):
                if k == "rings" and "rings" not in self:
                    return original_polygon_getitem(self, "curveRings")
                else:
                    return original_polygon_getitem(self, k)
            arcgis.geometry.Polygon.__getitem__ = _patched_polygon_getitem__
    except Exception as exc:
        __logger.error("Failed checking/patching arcgis.geometry.Polygon.__getitem__.", exc_info=exc)
    else:
        __logger.debug("Patched arcgis.geometry.Polygon.__getitem__.")

__patch()
