import numpy as np
from qgis.core import *

from geogst.core.geometries.georeferencing.geodetic import *


def distance_projected_pts(
        x,
        y,
        delta_x,
        delta_y,
        src_crs,
        dest_crs
):
    qgspt_start_src_crs = qgs_pt(x, y)
    qgspt_end_src_crs = qgs_pt(x + delta_x, y + delta_y)

    qgspt_start_dest_crs = project_qgs_point(qgspt_start_src_crs, src_crs, dest_crs)
    qgspt_end_dest_crs = project_qgs_point(qgspt_end_src_crs, src_crs, dest_crs)

    pt2_start_dest_crs = Point(
        qgspt_start_dest_crs.x(),
        qgspt_start_dest_crs.y()
    )

    pt2d_end_dest_crs = Point(
        qgspt_end_dest_crs.x(),
        qgspt_end_dest_crs.y()
    )

    return pt2_start_dest_crs.distance(pt2d_end_dest_crs)


def project_point(
        pt: Point,
        srcCrs: QgsCoordinateReferenceSystem,
        destCrs: QgsCoordinateReferenceSystem
) -> Point:

    qgs_pt = QgsPointXY(pt.x, pt.y)

    proj_qgs_pt = project_qgs_point(qgs_pt, srcCrs, destCrs)
    proj_x, proj_y = proj_qgs_pt.x(), proj_qgs_pt.y()

    return Point(
        proj_x,
        proj_y
    )


def project_qgs_point(
        qgsPt: QgsPointXY,
        srcCrs: QgsCoordinateReferenceSystem,
        destCrs: QgsCoordinateReferenceSystem
) -> QgsPointXY:

    return QgsCoordinateTransform(
        srcCrs,
        destCrs,
        QgsProject.instance()
    ).transform(qgsPt)


def read_qgis_pt_layer(
    pt_layer: QgsVectorLayer,
    field_list=None
) -> List:

    if field_list is None:
        field_list = []

    if pt_layer.selectedFeatureCount() > 0:
        features = pt_layer.selectedFeatures()
    else:
        features = pt_layer.getFeatures()

    provider = pt_layer.dataProvider()
    field_indices = [provider.fieldNameIndex(field_name) for field_name in field_list if field_name]

    # retrieve selected features with their geometry and relevant attributes
    rec_list = []
    for feature in features:

        pt = feature.geometry().vertexAt(0)
        x, y, z = pt.x(), pt.y(), pt.z()

        if z is None or not np.isfinite(z):
            feat_list = [x, y]
        else:
            feat_list = [x, y, z]

        # creates feature attribute list

        attrs = feature.fields().toList()

        for field_ndx in field_indices:
            feat_list.append(feature.attribute(attrs[field_ndx].name()))

        # add to result list
        rec_list.append(feat_list)

    return rec_list


def qgs_pt(x, y):

    return QgsPointXY(x, y)


def calculate_pts_in_projection(pts_in_orig_crs, srcCrs, destCrs):

    pts_in_prj_crs = []

    for pt in pts_in_orig_crs:
        qgs_pt = QgsPointXY(pt.x, pt.y)
        qgs_pt_prj_crs = project_qgs_point(qgs_pt, srcCrs, destCrs)
        pts_in_prj_crs.append(
            Point(
                qgs_pt_prj_crs.x(),
                qgs_pt_prj_crs.y()
            )
        )

    return pts_in_prj_crs

