"""
Finnhub provider
Free tier: 60 API calls/minute - good for real-time quotes
"""
from typing import Optional, List, Dict
from datetime import datetime
import requests
import pandas as pd

from .base import BaseProvider
from ..models import Quote, HistoricalData
from ..core import ProviderRateLimiter
from ..config import Config


class FinnhubProvider(BaseProvider):
    """Finnhub API provider"""
    
    BASE_URL = "https://finnhub.io/api/v1"
    
    def __init__(self, api_key: Optional[str] = None, rate_limiter: Optional[ProviderRateLimiter] = None):
        super().__init__("finnhub")
        self.rate_limiter = rate_limiter
        self.api_key = api_key or Config.FINNHUB_API_KEY
        
        if not self.api_key:
            self._available = False
            self._last_error = "Finnhub API key not configured"
        else:
            self._available = True
    
    def get_quote(self, symbol: str) -> Optional[Quote]:
        """Get real-time quote using /quote endpoint"""
        if not self._available:
            return None
        
        try:
            if self.rate_limiter:
                self.rate_limiter.wait_if_needed("finnhub")
            
            # Finnhub quote endpoint
            url = f"{self.BASE_URL}/quote"
            params = {
                "symbol": symbol,
                "token": self.api_key
            }
            
            response = requests.get(url, params=params, timeout=10)
            response.raise_for_status()
            
            data = response.json()
            
            # Check for error or empty data
            if not data or data.get("c") == 0:
                return None
            
            # Finnhub returns: c=current, h=high, l=low, o=open, pc=previous close, t=timestamp
            current_price = data.get("c")
            if not current_price:
                return None
            
            timestamp = datetime.fromtimestamp(data.get("t", datetime.now().timestamp()))
            
            quote = Quote(
                symbol=symbol,
                timestamp=timestamp,
                price=float(current_price),
                open=float(data.get("o", 0)) if data.get("o") else None,
                high=float(data.get("h", 0)) if data.get("h") else None,
                low=float(data.get("l", 0)) if data.get("l") else None,
                close=float(current_price),
                volume=None,  # Not provided in /quote endpoint
                change=float(data.get("d", 0)) if data.get("d") else None,
                change_percent=float(data.get("dp", 0)) if data.get("dp") else None,
                previous_close=float(data.get("pc", 0)) if data.get("pc") else None,
                source="finnhub",
                metadata={
                    "timestamp_raw": data.get("t")
                }
            )
            
            return quote
            
        except Exception as e:
            self._handle_error(e, f"get_quote({symbol})")
            return None
    
    def get_multiple_quotes(self, symbols: List[str]) -> List[Quote]:
        """
        Get quotes for multiple symbols.
        Note: Finnhub doesn't have native batch endpoint, so we make individual calls.
        Rate limit is generous (60/min) so this is acceptable.
        """
        if not self._available:
            return []
        
        quotes = []
        
        for symbol in symbols:
            quote = self.get_quote(symbol)
            if quote:
                quotes.append(quote)
        
        return quotes
    
    def get_historical(self,
                      symbol: str,
                      start: datetime,
                      end: datetime,
                      interval: str = "1d") -> Optional[HistoricalData]:
        """Get historical candles data"""
        if not self._available:
            return None
        
        try:
            if self.rate_limiter:
                self.rate_limiter.wait_if_needed("finnhub")
            
            # Map interval to Finnhub resolution
            resolution_map = {
                "1m": "1",
                "5m": "5",
                "15m": "15",
                "30m": "30",
                "1h": "60",
                "1d": "D",
                "1w": "W",
                "1M": "M"
            }
            resolution = resolution_map.get(interval, "D")
            
            # Finnhub candle endpoint
            url = f"{self.BASE_URL}/stock/candle"
            params = {
                "symbol": symbol,
                "resolution": resolution,
                "from": int(start.timestamp()),
                "to": int(end.timestamp()),
                "token": self.api_key
            }
            
            response = requests.get(url, params=params, timeout=10)
            response.raise_for_status()
            
            data = response.json()
            
            # Check status
            if data.get("s") != "ok" or not data.get("t"):
                return None
            
            # Convert to DataFrame
            df = pd.DataFrame({
                "Date": pd.to_datetime(data["t"], unit="s"),
                "Open": data["o"],
                "High": data["h"],
                "Low": data["l"],
                "Close": data["c"],
                "Volume": data["v"]
            })
            
            df = df.set_index("Date")
            
            return HistoricalData(
                symbol=symbol,
                data=df,
                start_date=start,
                end_date=end,
                interval=interval,
                source="finnhub"
            )
            
        except Exception as e:
            self._handle_error(e, f"get_historical({symbol})")
            return None
    
    # ========================================================================
    # Extended APIs - Finnhub specific features
    # ========================================================================
    
    def get_company_profile(self, symbol: str) -> Dict:
        """Get company profile"""
        if not self._available:
            return {}
        
        try:
            if self.rate_limiter:
                self.rate_limiter.wait_if_needed("finnhub")
            
            url = f"{self.BASE_URL}/stock/profile2"
            params = {
                "symbol": symbol,
                "token": self.api_key
            }
            
            response = requests.get(url, params=params, timeout=10)
            response.raise_for_status()
            
            return response.json()
            
        except Exception as e:
            self._handle_error(e, f"get_company_profile({symbol})")
            return {}
    
    def get_news(self, symbol: str, limit: int = 10) -> List[Dict]:
        """Get company news"""
        if not self._available:
            return []
        
        try:
            if self.rate_limiter:
                self.rate_limiter.wait_if_needed("finnhub")
            
            # Get date range (last 30 days)
            end = datetime.now()
            start = datetime(end.year, end.month, end.day) - pd.Timedelta(days=30)
            
            url = f"{self.BASE_URL}/company-news"
            params = {
                "symbol": symbol,
                "from": start.strftime("%Y-%m-%d"),
                "to": end.strftime("%Y-%m-%d"),
                "token": self.api_key
            }
            
            response = requests.get(url, params=params, timeout=10)
            response.raise_for_status()
            
            news = response.json()
            return news[:limit] if news else []
            
        except Exception as e:
            self._handle_error(e, f"get_news({symbol})")
            return []
    
    def get_recommendation_trends(self, symbol: str) -> List[Dict]:
        """Get recommendation trends (buy/sell/hold)"""
        if not self._available:
            return []
        
        try:
            if self.rate_limiter:
                self.rate_limiter.wait_if_needed("finnhub")
            
            url = f"{self.BASE_URL}/stock/recommendation"
            params = {
                "symbol": symbol,
                "token": self.api_key
            }
            
            response = requests.get(url, params=params, timeout=10)
            response.raise_for_status()
            
            return response.json()
            
        except Exception as e:
            self._handle_error(e, f"get_recommendation_trends({symbol})")
            return []
