import re
from typing import Union
import folium
import pandas as pd
from folium import plugins
import streamlit as st

EPICENTER_LOCATION = [31.12210171476489, -8.42945837915193]
BORDER_COLOR = "black"

# @st.cache_resource
def parse_gg_sheet(url):
    print("Parsing Google Sheet:", url)
    url = url.replace("edit#gid=", "export?format=csv&gid=")
    df = pd.read_csv(url, on_bad_lines="warn")
    return df

@st.cache_resource
def parse_json_file(url):
    df = pd.read_json(url)
    df = pd.json_normalize(df.douars)
    return df

def is_request_in_list(request, selection_list, options):
    if isinstance(request, float):  # Check if the input is a float (like NaN)
        return False

    if "," in request:
      all_requests = [r.strip() for r in request.split(",")]
    else:
      all_requests = [request]

    # If at least one of the requests is not in the options or in the selection list, return True
    for r in all_requests:
        if r not in options:
            return True
        if r in selection_list:
            return True
    return False

def add_latlng_col(df, process_column: Union[str, int]):
    """Add a latlng column to the dataframe"""
    if isinstance(process_column, str):
        df["latlng"] = df[process_column].apply(parse_latlng)
    elif isinstance(process_column, int):
        df["latlng"] = df.iloc[:, process_column].apply(parse_latlng)
    else:
        raise ValueError(f"process_column should be a string or an integer, got {type(process_column)}")
    return df

# parse latlng (column 4) to [lat, lng]
def parse_latlng(latlng):
    if pd.isna(latlng):
        return None
    try:
        # case where there more than one comma 30,98 , -7,10
        if latlng.count(',') > 2:
            d1, d2, d3, d4 = latlng.split(",")[:4]
            return [float(".".join([d1, d2])), float(".".join([d3, d4]))]

        # case of more than one dot 30.98. -7.10
        if latlng.count('.') > 2:
            d1, d2, d3, d4 = latlng.split(".")[:4]
            return [float(".".join([d1, d2])), float(".".join([d3, d4]))]

        # case where there is only one comma 30,98 , -7,10
        lat, lng = latlng.split(",")[:2]
        # remove anything that is not a digit or a dot or a minus sign
        lat = re.sub(r"[^\d\.\-]", "", lat)
        lng = re.sub(r"[^\d\.\-]", "", lng)
        return [float(lat), float(lng)]

    except Exception as e:
        print(f"Error parsing latlng: {latlng}  Reason: {e}")
        return None

def add_epicentre_to_map(fg):
    # Removed the spinner to not confuse the users as the map is already loaded
    icon_epicentre = folium.plugins.BeautifyIcon(
        icon='star',
        border_color='#b3334f',
        background_color='#b3334f',
        text_color='white'
    )

    fg.add_child(folium.Marker(location=EPICENTER_LOCATION,
                #   popup="Epicenter مركز الزلزال",
                  tooltip="Epicenter مركز الزلزال",
                  icon=icon_epicentre))



def add_danger_distances_to_map(map_obj):
    Danger_Distances_group = folium.FeatureGroup(name='Danger distances - earthquake magnitude 7 | مسافات الخطر - قوة الزلازل 7').add_to(map_obj)

    zones = [
        {"radius": 100000, "fill_opacity": 0.1, "weight": 1, "fill_color": "yellow", "tooltip": "50 to 100 km - Moderate risk area | منطقة خطر معتدلة"},
        {"radius": 50000, "fill_opacity": 0.1, "weight": 1, "fill_color": "orange", "tooltip": "30 to 50 km - High risk zone | منطقة عالية المخاطر"},
        {"radius": 30000, "fill_opacity": 0.2, "weight": 1, "fill_color": "#FF0000", "tooltip": "10 to 30 km - Very high risk zone | منطقة شديدة الخطورة"},
        {"radius": 10000, "fill_opacity": 0.2, "weight": 0.2, "fill_color": "#8B0000", "tooltip": "0 to 10km - direct impact zone | منطقة التأثير المباشر"}
    ]

    for zone in zones:
        folium.Circle(
            location=EPICENTER_LOCATION,
            radius=zone["radius"],
            color=BORDER_COLOR,
            weight=zone["weight"],
            fill_opacity=zone["fill_opacity"],
            opacity=zone["fill_opacity"],  # Assuming border opacity should match fill_opacity
            fill_color=zone["fill_color"],
            # tooltip=zone["tooltip"],
        ).add_to(Danger_Distances_group)


def add_village_names(douar_df, map_obj):
    village_fgroup = folium.FeatureGroup(name='🔵 All the Villages / جميع القرى', show=False).add_to(map_obj)

    for _, row in douar_df.iterrows():
        lat = row['lat']
        lng = row['lng']
        lat_lng = (lat, lng)
        dour_name = row['name'].capitalize()
        maps_url = f"https://maps.google.com/?q={lat_lng}"
        display_text = f'<br><b>⛰️ Douar:</b> {dour_name}<br><a href="{maps_url}" target="_blank" rel="noopener noreferrer"><b>🧭 Google Maps</b></a>'

        folium.CircleMarker(
            location=[lat, lng],
            radius=0.1,
            tooltip = dour_name, # we might remove the tooltip to avoid crowding the map
            popup=folium.Popup(display_text, max_width=200),
            color= "#0046C8",
            opacity = 0.7
        ).add_to(village_fgroup)


def init_intervention_fgs(m):
    intervention_fgs = {}

    fg_done = folium.FeatureGroup(name="Done ✅", show=True).add_to(m)
    fg_planned = folium.FeatureGroup(name="Planned ⏳", show=True).add_to(m)
    fg_partial = folium.FeatureGroup(name="Partial 📝", show=True).add_to(m)

    intervention_fgs["Done ✅"] = fg_done
    intervention_fgs["Planned ⌛"] = fg_planned
    intervention_fgs["Partial 📝"] = fg_partial

    return intervention_fgs


def init_emergency_fgs(m):
    emergency_fgs = {}

    fg_high = folium.FeatureGroup(name=_("High Emergency 🔴"), show=True).add_to(m)
    fg_medium = folium.FeatureGroup(name=_("Medium Emergency 🟠"), show=True).add_to(m)
    fg_low = folium.FeatureGroup(name=_("Low Emergency 🟡"), show=True).add_to(m)

    emergency_fgs["High"] = fg_high
    emergency_fgs["Medium"] = fg_medium
    emergency_fgs["Low"] = fg_low

    return emergency_fgs


def init_map():
    m = folium.Map(
        location=[31.228674, -7.992047],
        zoom_start=8.5,
        min_zoom=8.5,
        max_lat=35.628674,
        min_lat=29.628674,
        max_lon=-4.992047,
        min_lon=-10.992047,
        max_bounds=True,
    )
    # Add a search bar to the map
    geocoder = plugins.Geocoder(
        collapsed=False,
        position="topright",
        placeholder="Search | البحث",
    )
    m.add_child(geocoder)

    # Add Fullscreen button to the map
    fullscreen = plugins.Fullscreen(
        position="topright",
        title="Expand me | تكبير الخريطة",
        title_cancel="Exit me | تصغير الخريطة",
        force_separate_button=True,
    )
    m.add_child(fullscreen)

    # Satellite View from Mapbox
    tileurl = "https://marocmap.ikiker.com/maroc/{z}/{x}/{y}.png"
    folium.TileLayer(
        tiles=tileurl,
        attr="Maroc Map",
        name="Maroc Map",
        overlay=False,
        control=False,
    ).add_to(m)

    # Add danger zones
    add_epicentre_to_map(m)
    add_danger_distances_to_map(m)
    emergency_fgs = init_emergency_fgs(m)
    intervention_fgs = init_intervention_fgs(m)

    # Add a LayerControl to the map to toggle between layers (Satellite View and Default One)
    folium.LayerControl().add_to(m)

    # Add detect location button
    plugins.LocateControl(
        position="topleft",
        drawCircle=False,
        flyTo=True,
        strings={"title": "My location | موقعي", "popup": "My location | موقعي"},
    ).add_to(m)

    return m, emergency_fgs, intervention_fgs