from ._hail import *
from ._imports import *
from ._pconfig import pconfig

def get_hail_storm_polygon(cat_no, cat_date, save_gdf = False):
    hd = HailData(cat_date = cat_date)
    data = hd.get_hail_data()
    df, gdf = hd.extract_data_to_df(data)
    if save_gdf:
        path = pconfig['gis_file_folder']
        hd.save_data_csv(df, gdf, path= path )
        print(f"gdf have saved at {path}\hail_swath_{hd.file_timestamp}.gpkg")
    return gdf

def get_cat_geodataframe (gdf_cat_polygon, df_claim, df_policy):

    #create claim gdf
    geometry = [Point(xy) for xy in zip(df_claim['GEO_X'], df_claim['GEO_Y'])]
    # Convert to GeoDataFrame
    gdf_claim = gpd.GeoDataFrame(df_claim, geometry=geometry, crs="EPSG:4326") 

    #has claim in the swath    
    gdf_has_claim_inside_swath = gpd.sjoin(gdf_claim, gdf_cat_polygon, how="inner", predicate="within")  #now sure about join condition
    #gdf_has_claim_inside_swath[['CAT_NO', 'POLICY_NO', 'FILE_NO','LOSS_DT','diameter_in', 'diameter_in_label']]


    #has claim not in the hail swath
    gdf_has_claim_not_in_swath =  gdf_claim[~gdf_claim['POLICY_NO'].isin(gdf_has_claim_inside_swath['POLICY_NO'])]
    
    
    #create policy gdf
    geometry_h = [Point(xy) for xy in zip(df_policy['GEO_X'], df_policy['GEO_Y'])]
    # Convert to GeoDataFrame
    gdf_policy = gpd.GeoDataFrame(df_policy, geometry=geometry_h, crs="EPSG:4326") 
    

    #this is all policy inside swath
    joined_inner_policy = gpd.sjoin(gdf_policy, gdf_cat_polygon, how="inner", predicate="within")  #now sure about join condition
    
    #this is all policy inside swath but not have claim 
    gdf_has_no_claim_in_hailswath= joined_inner_policy[~joined_inner_policy['POLICY_NO'].isin(df_claim['POLICY_NO'].unique())]
    
    return gdf_has_claim_inside_swath, gdf_has_claim_not_in_swath, gdf_has_no_claim_in_hailswath 
    

#get distance and nearest polygon for all gdf has claim but not in swath

def convert_gdf_epsg (gdf,  target_epsg = 3857):
    gdf =  gdf.copy()
    #epsg_code = gdf.crs.to_epsg()
    #print(f'current epsg code is {epsg_code}')
    gdf = gdf.to_crs(epsg=target_epsg)
    return gdf

def get_nearest_polygon(query_point_geom, gdf):
    '''
    gdf is hail polygon from hail api, by default is crs 4326,need to convert to 3857 for distance calculation     
    query_point_geom from a gdf also need to convert to 3857
    '''
    gdf_dis = convert_gdf_epsg(gdf, 3857)    
    distances = gdf_dis.distance(query_point_geom)
    # Find the index of the minimum distance
    closest_polygon_index = distances.idxmin()
    # Retrieve the closest polygon as a GeoSeries or GeoDataFrame row
    closest_polygon = gdf_dis.loc[closest_polygon_index]
    return closest_polygon['geometry']

def get_nearest_distance_polygon(gdf_claim_not_in_swath, gdf_polygon):

    gdf_claim_not_in_swath_dis = convert_gdf_epsg(gdf_claim_not_in_swath, target_epsg = 3857)
    gdf_dis = convert_gdf_epsg(gdf_polygon, 3857)     
    nearest_geoms = gpd.sjoin_nearest(
        gdf_claim_not_in_swath_dis, #points_gdf, 
        gdf_dis ,#polygons_gdf, 
        how="left", 
        distance_col='distance_to_nearest_poly'  #"dist_to_polygon"
    )
    nearest_geoms.drop_duplicates(subset=['POLICY_NO'], keep='first', inplace=True)  #some show multiple row with distance as 0, possible at the edge?
    gdf_claim_not_in_swath['distance'] = nearest_geoms['distance_to_nearest_poly'] 
    gdf_claim_not_in_swath['nearest_polygon_diameter_in'] = nearest_geoms['diameter_in']
    gdf_claim_not_in_swath['nearest_polygon'] = gdf_claim_not_in_swath['geometry'].apply(lambda x: get_nearest_polygon(x,gdf_dis) )
    return gdf_claim_not_in_swath