"""
Simplified station discovery for PrecipGen.

Provides basic station discovery functionality without the bloat.
"""

import requests
import time
from typing import List, Dict, Optional, Tuple, Union
import pandas as pd
import numpy as np
from urllib.parse import quote

from ..data.ghcn_downloader import GHCNDownloader
from ..utils.exceptions import GeocodingError, StationDiscoveryError
from ..config.precipgen_config import StationRequirements
from ..api.data_exchange import StationInfo


class SimpleGeocoder:
    """Simple geocoding using OpenStreetMap Nominatim API."""
    
    def __init__(self):
        self.base_url = "https://nominatim.openstreetmap.org/search"
        self.last_request_time = 0
        self.min_request_interval = 1.0  # Respect rate limits
    
    def geocode(self, location_string: str) -> Tuple[float, float]:
        """
        Convert location string to coordinates.
        
        Args:
            location_string: City name or address
            
        Returns:
            Tuple of (latitude, longitude)
        """
        # Rate limiting
        elapsed = time.time() - self.last_request_time
        if elapsed < self.min_request_interval:
            time.sleep(self.min_request_interval - elapsed)
        
        try:
            params = {
                'q': location_string,
                'format': 'json',
                'limit': 1,
                'addressdetails': 1
            }
            
            headers = {'User-Agent': 'PrecipGen/0.1.3'}
            
            response = requests.get(self.base_url, params=params, headers=headers, timeout=10)
            self.last_request_time = time.time()
            
            response.raise_for_status()
            results = response.json()
            
            if not results:
                raise GeocodingError(f"No results found for: {location_string}")
            
            result = results[0]
            lat = float(result['lat'])
            lon = float(result['lon'])
            
            return lat, lon
            
        except requests.RequestException as e:
            raise GeocodingError(f"Geocoding failed: {e}") from e
        except (KeyError, ValueError, IndexError) as e:
            raise GeocodingError(f"Invalid geocoding response: {e}") from e


class SimpleStationDiscovery:
    """
    Simplified station discovery for finding GHCN stations.
    
    Provides basic station finding without complex ranking algorithms.
    """
    
    def __init__(self):
        self.geocoder = SimpleGeocoder()
        self.downloader = GHCNDownloader()
        
        # Known good stations for common cities (fallback)
        self.known_stations = {
            'seattle': ('USW00024233', 'Seattle Tacoma International Airport'),
            'salt lake city': ('USW00024127', 'Salt Lake City International Airport'),
            'portland': ('USW00024229', 'Portland International Airport'),
            'san francisco': ('USW00023234', 'San Francisco International Airport'),
            'denver': ('USW00023062', 'Denver International Airport'),
            'chicago': ('USW00014819', 'Chicago O\'Hare International Airport'),
            'new york': ('USW00014732', 'New York LaGuardia Airport'),
            'los angeles': ('USW00023174', 'Los Angeles International Airport'),
            'miami': ('USW00012839', 'Miami International Airport'),
            'phoenix': ('USW00023183', 'Phoenix Sky Harbor International Airport')
        }
    
    def find_station(self, 
                    location: Union[str, Tuple[float, float]],
                    requirements: Optional[StationRequirements] = None) -> StationInfo:
        """
        Find the best GHCN station for a location.
        
        Args:
            location: City name or (lat, lon) coordinates
            requirements: Station requirements
            
        Returns:
            StationInfo for the best station found
        """
        requirements = requirements or StationRequirements()
        
        # Handle string locations
        if isinstance(location, str):
            # Check known stations first
            location_lower = location.lower()
            for city, (station_id, station_name) in self.known_stations.items():
                if city in location_lower:
                    return self._create_station_info(station_id, station_name, location)
            
            # Geocode if not in known stations
            try:
                lat, lon = self.geocoder.geocode(location)
                coordinates = (lat, lon)
            except GeocodingError:
                raise StationDiscoveryError(f"Could not geocode location: {location}")
        else:
            coordinates = location
        
        # For now, return the closest known station
        # In a full implementation, this would search the GHCN station database
        closest_station = self._find_closest_known_station(coordinates)
        if closest_station:
            station_id, station_name = closest_station
            return self._create_station_info(station_id, station_name, coordinates)
        
        raise StationDiscoveryError(f"No suitable station found for location: {location}")
    
    def _find_closest_known_station(self, coordinates: Tuple[float, float]) -> Optional[Tuple[str, str]]:
        """Find the closest known station to given coordinates."""
        lat, lon = coordinates
        
        # Approximate coordinates for known stations
        station_coords = {
            ('USW00024233', 'Seattle Tacoma International Airport'): (47.4502, -122.3088),
            ('USW00024127', 'Salt Lake City International Airport'): (40.7899, -111.9791),
            ('USW00024229', 'Portland International Airport'): (45.5898, -122.5951),
            ('USW00023234', 'San Francisco International Airport'): (37.6213, -122.3790),
            ('USW00023062', 'Denver International Airport'): (39.8561, -104.6737),
            ('USW00014819', 'Chicago O\'Hare International Airport'): (41.9742, -87.9073),
            ('USW00014732', 'New York LaGuardia Airport'): (40.7769, -73.8740),
            ('USW00023174', 'Los Angeles International Airport'): (33.9425, -118.4081),
            ('USW00012839', 'Miami International Airport'): (25.7959, -80.2870),
            ('USW00023183', 'Phoenix Sky Harbor International Airport'): (33.4342, -112.0116)
        }
        
        min_distance = float('inf')
        closest_station = None
        
        for (station_id, station_name), (s_lat, s_lon) in station_coords.items():
            # Simple distance calculation (not great circle, but adequate for this purpose)
            distance = np.sqrt((lat - s_lat)**2 + (lon - s_lon)**2)
            if distance < min_distance:
                min_distance = distance
                closest_station = (station_id, station_name)
        
        return closest_station
    
    def _create_station_info(self, station_id: str, station_name: str, 
                           location: Union[str, Tuple[float, float]]) -> StationInfo:
        """Create StationInfo object with basic information."""
        # For now, return basic info
        # In full implementation, this would query station metadata
        
        if isinstance(location, tuple):
            lat, lon = location
        else:
            # Use approximate coordinates for known stations
            lat, lon = 40.0, -100.0  # Default to center of US
        
        return StationInfo(
            id=station_id,
            name=station_name,
            latitude=lat,
            longitude=lon,
            elevation_m=None,
            distance_km=0.0,
            data_years=30,  # Placeholder
            first_year=1990,  # Placeholder
            last_year=2020,  # Placeholder
            data_completeness=0.95,  # Placeholder
            data_quality_score=0.90,  # Placeholder
            quality_flags=[],
            station_type="Airport",
            network="GHCN",
            country="US"
        )