# -*- encoding=utf-8 -*-
""" Utilities to manage shapefile layers
"""
import os
import logging

from .errors import InvalidLayerError
from .sql import create_database, connect_database
from qgis._core import QgsCoordinateTransformContext
from qgis.core import QgsDataSourceUri, QgsVectorLayer, QgsVectorFileWriter
from .processing_on_layer import check_validity_algorithm


def check_layer(layer: QgsVectorLayer, wkbtypes) -> None:
    """ Check layer validity
    """
    number_of_errors = check_validity_algorithm(layer)
    if number_of_errors > 0:
        logging.warning("Input layer contain invalid geometries")

    if wkbtypes and layer.wkbType() not in wkbtypes:
        raise InvalidLayerError(f"Invalid geometry type for layer {layer.wkbType()}")

    if layer.crs().isGeographic():
       raise InvalidLayerError("Invalid CRS (lat/long) for layer")


def import_as_layer(db_path: str, layer, name, forceSinglePartGeometryType=False) -> None:
    """
    """
    from qgis.core import QgsDataSourceUri, QgsVectorLayer, QgsVectorLayerExporter
    if isinstance(layer, QgsVectorLayer):
        # Create database if it does not exists
        create_database(db_path)

        # Create Spatialite URI
        uri = QgsDataSourceUri()
        uri.setDatabase(db_path)
        uri.setDataSource('', name, 'GEOMETRY')
        opts = {}
        opts['overwrite'] = True
        opts['forceSinglePartGeometryType'] = forceSinglePartGeometryType
        error, errMsg = QgsVectorLayerExporter.exportLayer(layer, uri.uri(False), 'spatialite', layer.crs(), False, options=opts)
        if error != QgsVectorLayerExporter.NoError:
            raise IOError(f"Failed to add layer to database '{db_path}': error {errMsg}")
    else:
        import_shapefile(db_path, layer, name)


def import_shapefile(dbname, path, name, forceSinglePartGeometryType=False):
    """ Add shapefile as new table in database

        :param dbname: Path of the database
        :param path: Path of the shapefile
        :param name: Name of the table
    """
    # Import with QGIS API
    from qgis.core import QgsDataSourceUri, QgsVectorLayer, QgsVectorLayerExporter

    # Create shapefile QgsVectorLayer
    if not os.path.exists(path):
        raise IOError(f"Failed to read shapefile '{path}'")
    layer = QgsVectorLayer(path, name, 'ogr')
    if not layer.isValid():
        raise IOError(f"Shapefile '{path}' is not valid")

    # create spatialite database if does not exist
    create_database(dbname)

    # Create Spatialite URI
    uri = QgsDataSourceUri()
    uri.setDatabase(dbname)
    uri.setDataSource('', name, 'GEOMETRY')
    opts = {}
    opts['overwrite'] = True
    opts['forceSinglePartGeometryType'] = forceSinglePartGeometryType
    error, errMsg = QgsVectorLayerExporter.exportLayer(layer, uri.uri(False), 'spatialite', layer.crs(), False, options=opts)
    if error != QgsVectorLayerExporter.NoError:
        raise IOError(f"Failed to add layer to database '{dbname}': error {errMsg}")

    # Add spatial index
    conn = connect_database(dbname)
    cur  = conn.cursor()
    cur.execute(f"SELECT CreateSpatialIndex('{name}', 'GEOMETRY')")
    cur.close()
    conn.close()
    del cur
    del conn


def export_as_geopakage(dbname: str, table: str, output: str):
    """ Save spatialite table as geopakage

        :param dbname: Database path
        :param table: The table name
        :param output: Output path of the destination folder to store geopakage
    """

    # Create Spatialite URI
    uri = QgsDataSourceUri()
    uri.setDatabase(dbname)
    uri.setDataSource('', table, 'GEOMETRY')

    # Create Spatialite QgsVectorLayer
    dblayer = QgsVectorLayer(uri.uri(), table, 'spatialite')

    # Geopakage path
    geopakage = os.path.join(output, f"{table}_{os.path.basename(output)}.gpkg")

    # Options (file format, encoding)
    options = QgsVectorFileWriter.SaveVectorOptions()
    options.driverName = "GPKG"
    options.fileEncoding = "UTF-8"

    # Write Geopakage
    writeError = QgsVectorFileWriter.writeAsVectorFormatV3(dblayer, geopakage, QgsCoordinateTransformContext(), options)
    if writeError[0] != 0:
        logging.error(f" error code {writeError[0]} : {writeError[1]}")
        raise IOError(f"Failed to save '{dbname}:{table}' as  '{output}'")
