# map.py
#
# author: deng
# date: 20251127

from typing import Optional

import folium


class MapRenderer:
    """Render hiking routes on interactive maps."""

    def __init__(self) -> None:
        """Initialize map renderer."""
        pass

    def create_route_map(
        self,
        points: list[tuple[float, float]],
        start_point: Optional[tuple[float, float, float]],
        end_point: Optional[tuple[float, float, float]],
        waypoints: Optional[list[dict]] = None,
        tile_layer: str = 'OpenStreetMap',
    ) -> Optional[folium.Map]:
        """Create an interactive map with the hiking route.

        Args:
            points: List of (latitude, longitude) tuples for the route
            start_point: (latitude, longitude) tuple for start
            end_point: (latitude, longitude) tuple for end
            waypoints: List of waypoint dictionaries with 'lat', 'lon', 'name', 'elevation'
            tile_layer: Map tile layer to use ('OpenStreetMap' or 'RudyMap')

        Returns:
            folium.Map: Interactive map object
        """
        if not points or len(points) < 2:
            return None

        # Calculate center of the route
        center_lat = sum(p[0] for p in points) / len(points)
        center_lon = sum(p[1] for p in points) / len(points)

        # Create map obj
        route_map = folium.Map(
            location=[center_lat, center_lon],
            zoom_start=13,
            tiles=None,
        )

        # Add OpenStreetMap layer
        folium.TileLayer(
            tiles='OpenStreetMap',
            name='平面（OpenStreetMap）',
            overlay=False,
            control=True,
            show=tile_layer == 'OpenStreetMap',
        ).add_to(route_map)

        # Add Rudy Map (魯地圖) layer
        folium.TileLayer(
            tiles='https://tile.happyman.idv.tw/map/moi_osm/{z}/{x}/{y}.png',
            attr='&copy; <a href="https://rudy.basecamp.tw/">魯地圖</a>',
            name='等高線（魯地圖）',
            overlay=False,
            control=True,
            show=tile_layer == 'RudyMap',
            max_zoom=18,
        ).add_to(route_map)

        # Add layer control to switch between maps
        folium.LayerControl(position='topright').add_to(route_map)

        # Add the route as a red polyline
        folium.PolyLine(
            locations=points,
            color='red',
            weight=4,
            opacity=0.8,
            tooltip='登山路線',
        ).add_to(route_map)

        # Add waypoints if provided
        if waypoints:
            for waypoint in waypoints:
                popup_text = f'<b>{waypoint["name"]}</b>'
                if waypoint.get('elevation'):
                    popup_text += f'<br>海拔: {waypoint["elevation"]} m'

                folium.Marker(
                    location=[waypoint['lat'], waypoint['lon']],
                    popup=folium.Popup(popup_text, max_width=200),
                    tooltip=waypoint['name'],
                    icon=folium.Icon(color='orange', icon='info-sign'),
                ).add_to(route_map)

        # Add start point marker (blue circle)
        if start_point:
            folium.CircleMarker(
                location=(start_point[0], start_point[1]),
                radius=8,
                color='blue',
                fill=True,
                fill_color='blue',
                fill_opacity=0.7,
                popup=folium.Popup(f'<b>起點</b><br>海拔: {start_point[2]} m', max_width=200),
                tooltip='起點',
            ).add_to(route_map)

        # Add end point marker (blue circle)
        if end_point:
            folium.CircleMarker(
                location=(end_point[0], end_point[1]),
                radius=8,
                color='blue',
                fill=True,
                fill_color='blue',
                fill_opacity=0.7,
                popup=folium.Popup(f'<b>終點</b><br>海拔: {end_point[2]} m', max_width=200),
                tooltip='終點',
            ).add_to(route_map)

        # Fit bounds to show entire route
        route_map.fit_bounds(points)

        return route_map

    def add_hover_marker(self, route_map: folium.Map, position: tuple[float, float], label: str = '當前位置') -> folium.Map:
        """Add a hover position marker to the map.

        Args:
            route_map: Existing folium map
            position: (latitude, longitude) tuple for the marker
            label: Label for the marker

        Returns:
            folium.Map: Map with added marker
        """
        if position and route_map:
            folium.CircleMarker(
                location=position,
                radius=10,
                color='orange',
                fill=True,
                fill_color='orange',
                fill_opacity=0.9,
                popup=label,
                tooltip=label,
                weight=3,
            ).add_to(route_map)

        return route_map
