
from typing import Tuple, Union
import numbers

from osgeo import osr

from qgis.core import *
from qgis.core import Qgis
from qgis.core import QgsMessageLog


def extract_project_authid() -> Union[None, Tuple[str, numbers.Number]]:

    try:

        ai = QgsProject.instance().crs().authid()
        authority, code_as_string = ai.split(':')
        return authority, int(code_as_string)

    except Exception as e:

        QgsMessageLog.logMessage(
            f"Error extracting project authid: {e!r}",
            "qgSurf",
            Qgis.MessageLevel.Warning
        )
        return None

def extract_crs_of_project():

    return QgsProject.instance().crs()


def extract_project_crs_as_wkt() -> Union[None, str]:

    try:
        return QgsProject.instance().crs().toWkt()
    except Exception as e:
        QgsMessageLog.logMessage(
            f"Error extracting project CRS as WKT: {e!r}",
            "qgSurf",
            Qgis.MessageLevel.Warning
        )
        return None


def projectHasValidCrs() -> bool:

    return QgsProject.instance().crs().isValid()


def projectHasGeographicCrs() -> bool:

    return QgsProject.instance().crs().isGeographic()


def check_project_planar_crs() -> Tuple[bool, str]:

    project = QgsProject.instance()

    if project.count() == 0:
        msg = "Is a project open or has layers loaded?"
        return False, msg

    curr_proj_crs = project.crs()

    if not curr_proj_crs.isValid():
        msg = "Current project crs is not valid.\nPlease apply a valid crs to the current project."
        return False, msg

    if curr_proj_crs.isGeographic():
        msg = "Current project crs is geographic.\nPlease apply a planar crs to the current project."
        return False, msg

    msg = "Project open and with planar crs defined."
    return True, msg


def loaded_layers():

    return list(QgsProject.instance().mapLayers().values())


def loaded_vector_layers():

    return [layer for layer in loaded_layers() if layer.type() == QgsMapLayer.LayerType.VectorLayer]


def loaded_polygon_layers():

    return [layer for layer in loaded_vector_layers() if layer.geometryType() == QgsWkbTypes.GeometryType.PolygonGeometry]


def loaded_line_layers():

    return [layer for layer in loaded_vector_layers() if layer.geometryType() == QgsWkbTypes.GeometryType.LineGeometry]


def loaded_point_layers():

    return [layer for layer in loaded_vector_layers() if layer.geometryType() == QgsWkbTypes.GeometryType.PointGeometry]


def loaded_3d_vector_layers():

    return [layer for layer in loaded_vector_layers() if QgsWkbTypes.hasZ(layer.wkbType())]


def loaded_raster_layers():

    return [layer for layer in loaded_layers() if layer.type() == QgsMapLayer.LayerType.RasterLayer]


def get_dict_of_monoband_raster_layers():

    return {layer.name(): layer for layer in loaded_raster_layers() if layer.bandCount() == 1}


def loaded_monoband_raster_layers():

    return [layer for layer in loaded_raster_layers() if layer.bandCount() == 1]


def proj4str():

    project_crs = QgsProject.instance().crs()
    proj4_str = str(project_crs.toProj4())
    project_crs_osr = osr.SpatialReference()
    project_crs_osr.ImportFromProj4(proj4_str)

    return project_crs_osr
