import rasterio
import fiona
import geopandas as gpd


def get_rast_vals_point(rst_file, points, attr='rst_value'):

    # open raster
    src = rasterio.open(rst_file)

    # CRS check and reproject points if necessary
    if src.crs.to_epsg() != points.crs.to_epsg():
        ori_crs = points.crs.to_epsg()
        points = points.to_crs(src.crs.to_epsg())
    else:
        ori_crs = None

    # get point coordinates
    coords = [(x, y) for x, y in zip(points.geometry.x, points.geometry.y)]

    # sample raster at point locations
    points[attr] = [x[0] for x in src.sample(coords)]

    # back to original CRS
    if ori_crs is not None:
        points = points.to_crs(ori_crs)

    return points


def rast2poly(raster_file, vector_file, driver='GPKG',
              mask_value=None, geom_type='Polygon',
              attr='raster_val'):

    from rasterio.features import shapes

    with rasterio.open(raster_file) as src:
        image = src.read(1)

    if mask_value is not None:
        mask = image == mask_value
    else:
        mask = None

    results = (
        {'properties': {attr: v}, 'geometry': s}
        for i, (s, v)
        in enumerate(
            shapes(image, mask=mask, transform=src.transform)))

    with fiona.open(
            vector_file, 'w',
            driver=driver,
            crs=src.crs,
            schema={'properties': [(attr, 'float')],
                    'geometry': 'Polygon'}) as dst:
        dst.writerecords(results)

    gdf = gpd.read_file(vector_file)

    if geom_type == 'Point':
        gdf.geometry = gdf.geometry.centroid
        gdf.to_file(vector_file, driver=driver)

    return gdf
