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

import streamlit as st
import yaml
from elevation_profile import ElevationProfileRenderer
from gpx import GPXProcessor
from map_render import MapRenderer
from streamlit_folium import st_folium
from weather import WeatherFetcher


class HikingAssistant:
    def __init__(self):
        self._config = self._load_config()

    def _load_config(self):
        with open('assets/config.yaml', 'r') as f:
            return yaml.safe_load(f)

    def run(self):
        """Hiking Assistant application"""
        # Page configuration
        st.set_page_config(
            page_title=self._config['app']['page_title'],
            page_icon=self._config['app']['page_favicon_path'],
            layout='wide',
            initial_sidebar_state='collapsed',
        )

        # Title and description
        st.title('⛰️ ' + self._config['app']['page_title'])

        # File uploader
        uploaded_file = st.file_uploader(
            '上傳您的 GPX 檔案開始分析路線！',
            type=['gpx'],
            help='可以從[健行筆記](https://hiking.biji.co/index.php?q=trail&act=gpx_list)、'
            '[Hikingbook](https://zh-tw.hikingbook.net/explore/trails?regions=Taiwan)等網站下載 GPX 檔案',
        )

        if uploaded_file is not None:
            try:
                # Process GPX file
                with st.spinner('正在解析 GPX 檔案...'):
                    gpx_processor = GPXProcessor(uploaded_file)

                    if not gpx_processor.validate_and_parse():
                        st.error('❌ GPX 檔案格式錯誤或不包含有效的軌跡點')
                        return

                    # Calculate statistics
                    total_distance = gpx_processor.calculate_distance()
                    elevation_gain, elevation_loss = gpx_processor.calculate_elevation_gain_loss()
                    min_elevation, max_elevation = gpx_processor.get_min_max_elevation()
                    start_point, end_point = gpx_processor.get_start_end_points()
                    all_points = gpx_processor.get_all_points()
                    distances, elevations = gpx_processor.get_elevation_profile_data()
                    gradients = gpx_processor.get_gradients()
                    estimated_time = gpx_processor.calculate_naismith_time()

                # Display statistics section
                st.header('📊 路線五四三')
                col1, col2, col3, col4, col5, col6 = st.columns(6)

                with col1:
                    st.metric(label='總距離', value=f'{total_distance:.1f}km')

                with col2:
                    st.metric(label='總爬升', value=f'{elevation_gain:.0f}m')

                with col3:
                    st.metric(label='總下降', value=f'{elevation_loss:.0f}m')

                with col4:
                    st.metric(label='最高海拔', value=f'{max_elevation:.0f}m')

                with col5:
                    st.metric(label='最低海拔', value=f'{min_elevation:.0f}m')

                with col6:
                    st.metric(
                        label='預估行進時間',
                        value=f'{estimated_time // 60}h {estimated_time % 60}m',
                        help='依據[Naismith’s Rule](https://en.wikipedia.org/wiki/Naismith%27s_rule)計算',
                    )

                # Map section
                with st.spinner('正在渲染地圖...'):
                    map_renderer = MapRenderer()
                    route_map = map_renderer.create_route_map(all_points, start_point, end_point)

                    if route_map:
                        st_folium(route_map, width=None, height=500, key='route_map', returned_objects=[])
                    else:
                        st.error('無法渲染地圖')

                # Create two columns: elevation profile on left, pie chart on right
                profile_col, pie_col = st.columns([2, 1])

                with profile_col:
                    with st.spinner('正在繪製海拔剖面圖...'):
                        profile_renderer = ElevationProfileRenderer()
                        elevation_fig = profile_renderer.create_elevation_profile(distances, elevations, gradients)

                        if elevation_fig:
                            # elevation_fig = profile_renderer.add_gradient_legend(elevation_fig)
                            st.plotly_chart(elevation_fig, width='stretch')
                        else:
                            st.error('無法繪製海拔剖面圖')

                with pie_col:
                    with st.spinner('正在分析坡度分布...'):
                        pie_fig = profile_renderer.create_gradient_pie_chart(distances, gradients)

                        if pie_fig:
                            st.plotly_chart(pie_fig, width='stretch')
                        else:
                            st.error('無法繪製坡度分布圖')

                st.divider()

                # Weather section
                st.header('☀️ 天氣安抓')

                if start_point:
                    with st.spinner('正在獲取天氣資訊...'):
                        weather_fetcher = WeatherFetcher()
                        weather_data = weather_fetcher.get_weather(start_point[0], start_point[1])

                        if weather_data:
                            weather_info = weather_fetcher.format_weather_display(weather_data)

                            if weather_info:
                                # Current weather
                                st.subheader('此刻起點天氣')
                                col1, col2, col3, col4, col5 = st.columns(5)

                                with col1:
                                    st.metric(label='🌡️ 溫度', value=weather_info['temperature'])

                                with col2:
                                    st.metric(label='💧 濕度', value=weather_info['humidity'])

                                with col3:
                                    # Get precipitation probability from weather_data
                                    precip_prob = weather_data.get('current_precipitation_prob')
                                    if precip_prob is not None:
                                        st.metric(label='☔ 降雨機率', value=f'{precip_prob}%')
                                    else:
                                        st.metric(label='☔ 降雨機率', value='N/A')

                                with col4:
                                    st.metric(label='🌧️ 降雨量', value=weather_info['precipitation'])

                                with col5:
                                    # Get wind direction and convert to flow direction
                                    wind_dir_degrees = weather_data.get('current_wind_direction')
                                    wind_dir_text = weather_fetcher.convert_wind_degrees_to_flow_direction(wind_dir_degrees)

                                    # Get wind speed and level indicator
                                    wind_speed_value = weather_data.get('current_wind_speed')
                                    wind_level = weather_fetcher.get_wind_speed_indicator(wind_speed_value)

                                    st.metric(
                                        label='💨 風速與流向',
                                        value=f'{weather_info["wind_speed"]} {wind_dir_text} {wind_level}',
                                    )

                                # Forecast
                                if weather_info['forecast']:
                                    st.subheader('未來三天預報')
                                    forecast_cols = st.columns(3)

                                    for idx, forecast in enumerate(weather_info['forecast']):
                                        with forecast_cols[idx]:
                                            st.markdown(f'**{forecast["date"]}**')
                                            st.write(f'🌡️ 高溫: {forecast["temp_max"]}°C')
                                            st.write(f'🌡️ 低溫: {forecast["temp_min"]}°C')
                                            st.write(f'☔ 降雨機率: {forecast["precip_prob"]}%')
                            else:
                                st.warning('⚠️ 無法格式化天氣資料')
                        else:
                            st.warning('⚠️ 無法獲取天氣資訊，請稍後再試')
                else:
                    st.warning('⚠️ 無法確定起點位置')

            except Exception as e:
                st.error(f'❌ 處理檔案時發生錯誤: {str(e)}')

        st.divider()
        footer_text = f'<div style="text-align:center; font-size: 0.8em"><p>{self._config["app"]["page_footer_text"]}</p></div>'
        st.markdown(footer_text, unsafe_allow_html=True)


if __name__ == '__main__':
    app = HikingAssistant()
    app.run()
