import requests
import json
from datetime import datetime, timedelta
from typing import Annotated, Dict, List, Optional
from .config import get_api_key, DATA_DIR
from .external_data_logger import log_external_error, log_api_error
import os
import pandas as pd


def get_fred_api_key():
    """Get FRED API key from config or environment"""
    try:
        api_key = get_api_key("fred_api_key", "FRED_API_KEY")
        # print(f"FRED API key: {api_key}")
    except:
        api_key = None
    if not api_key:
        api_key = os.getenv("FRED_API_KEY")
    return api_key


def get_fred_data(series_id: str, start_date: str, end_date: str) -> Dict:
    """
    Get economic data from FRED API

    Args:
        series_id: FRED series ID (e.g., 'FEDFUNDS', 'CPIAUCSL')
        start_date: Start date in YYYY-MM-DD format
        end_date: End date in YYYY-MM-DD format

    Returns:
        Dictionary with FRED data
    """
    api_key = get_fred_api_key()
    if not api_key:
        return {"error": "FRED API key not found. Please set FRED_API_KEY environment variable."}


    url = "https://api.stlouisfed.org/fred/series/observations"
    params = {
        'series_id': series_id,
        'api_key': api_key,
        'file_type': 'json',
        'observation_start': start_date,
        'observation_end': end_date,
        'sort_order': 'desc',
        'limit': 100
    }
    
    try:
        response = requests.get(url, params=params)
        response.raise_for_status()
        return response.json()
    except Exception as e:
        log_api_error(
            system="fred",
            operation="get_fred_data",
            error_message=f"Failed to fetch FRED data for {series_id}: {str(e)}",
            symbol=series_id
        )
        return {"error": f"Failed to fetch FRED data for {series_id}: {str(e)}"}


def get_treasury_yield_curve(curr_date: str) -> str:
    """
    Get current Treasury yield curve data
    
    Args:
        curr_date: Current date in YYYY-MM-DD format
        
    Returns:
        Formatted string with yield curve data
    """
    # Treasury yield series IDs
    yield_series = {
        "1 Month": "DGS1MO",
        "3 Month": "DGS3MO", 
        "6 Month": "DGS6MO",
        "1 Year": "DGS1",
        "2 Year": "DGS2",
        "3 Year": "DGS3",
        "5 Year": "DGS5",
        "7 Year": "DGS7",
        "10 Year": "DGS10",
        "20 Year": "DGS20",
        "30 Year": "DGS30"
    }
    
    start_date = (datetime.strptime(curr_date, "%Y-%m-%d") - timedelta(days=30)).strftime("%Y-%m-%d")
    
    result = f"## Treasury Yield Curve as of {curr_date}\n\n"
    
    yield_data = []
    for maturity, series_id in yield_series.items():
        data = get_fred_data(series_id, start_date, curr_date)
        
        if "error" in data:
            continue
            
        observations = data.get("observations", [])
        if observations:
            latest = observations[0]
            if latest.get("value") != ".":
                yield_data.append({
                    "maturity": maturity,
                    "yield": float(latest["value"]),
                    "date": latest["date"]
                })
    
    if yield_data:
        result += "| Maturity | Yield (%) | Date |\n"
        result += "|----------|-----------|------|\n"
        
        for item in yield_data:
            result += f"| {item['maturity']} | {item['yield']:.2f}% | {item['date']} |\n"
        
        # Calculate yield curve analysis
        result += "\n### Yield Curve Analysis\n"
        
        # Find 2Y and 10Y for inversion check
        two_year = next((item for item in yield_data if item["maturity"] == "2 Year"), None)
        ten_year = next((item for item in yield_data if item["maturity"] == "10 Year"), None)
        
        if two_year and ten_year:
            spread = ten_year["yield"] - two_year["yield"]
            result += f"- **2Y-10Y Spread**: {spread:.2f} basis points\n"
            
            if spread < 0:
                result += "- **⚠️ INVERTED YIELD CURVE**: Potential recession signal\n"
            elif spread < 50:
                result += "- **📊 FLAT YIELD CURVE**: Economic uncertainty\n"
            else:
                result += "- **📈 NORMAL YIELD CURVE**: Healthy economic expectations\n"
    else:
        result += "No recent yield curve data available.\n"
    
    return result


def get_economic_indicators_report(curr_date: str, lookback_days: int = 90) -> str:
    """
    Get comprehensive economic indicators report
    
    Args:
        curr_date: Current date in YYYY-MM-DD format
        lookback_days: How many days to look back for data
        
    Returns:
        Formatted string with economic indicators
    """
    start_date = (datetime.strptime(curr_date, "%Y-%m-%d") - timedelta(days=lookback_days)).strftime("%Y-%m-%d")
    
    # Key economic indicators
    indicators = {
        "Federal Funds Rate": {
            "series": "FEDFUNDS",
            "description": "Federal Reserve's target interest rate",
            "unit": "%"
        },
        "Consumer Price Index (CPI)": {
            "series": "CPIAUCSL",
            "description": "Inflation measure based on consumer goods",
            "unit": "Index",
            "yoy": True
        },
        "Producer Price Index (PPI)": {
            "series": "PPIACO",
            "description": "Inflation measure at producer level",
            "unit": "Index",
            "yoy": True
        },
        "Unemployment Rate": {
            "series": "UNRATE",
            "description": "Percentage of labor force unemployed",
            "unit": "%"
        },
        "Nonfarm Payrolls": {
            "series": "PAYEMS",
            "description": "Monthly change in employment",
            "unit": "Thousands",
            "mom": True
        },
        "GDP Growth Rate": {
            "series": "GDP",
            "description": "Gross Domestic Product growth",
            "unit": "Billions",
            "qoq": True
        },
        "Industrial Production: Manufacturing": {
            "series": "IPMAN",
            "description": "Manufacturing sector output indicator",
            "unit": "Index (2017=100)"
        },
        "Consumer Confidence": {
            "series": "CSCICP03USM665S",
            "description": "Consumer sentiment indicator",
            "unit": "Index"
        },
        "VIX": {
            "series": "VIXCLS",
            "description": "Market volatility index",
            "unit": "Index"
        }
    }
    
    result = f"## Economic Indicators Report ({start_date} to {curr_date})\n\n"
    
    for indicator_name, config in indicators.items():
        data = get_fred_data(config["series"], start_date, curr_date)
        
        if "error" in data:
            result += f"### {indicator_name}\n**Error**: {data['error']}\n\n"
            continue
        
        observations = data.get("observations", [])
        if not observations:
            result += f"### {indicator_name}\n**No data available**\n\n"
            continue
        
        # Filter out missing values
        valid_obs = [obs for obs in observations if obs.get("value") != "."]
        if not valid_obs:
            result += f"### {indicator_name}\n**No valid data available**\n\n"
            continue
        
        latest = valid_obs[0]
        latest_value = float(latest["value"])
        latest_date = latest["date"]
        
        result += f"### {indicator_name}\n"
        result += f"- **Latest Value**: {latest_value:.2f} {config['unit']} (as of {latest_date})\n"
        result += f"- **Description**: {config['description']}\n"
        
        # Calculate changes if we have enough data
        if len(valid_obs) >= 2:
            previous = valid_obs[1]
            previous_value = float(previous["value"])
            change = latest_value - previous_value
            change_pct = (change / previous_value) * 100 if previous_value != 0 else 0
            
            result += f"- **Change**: {change:+.2f} {config['unit']} ({change_pct:+.2f}%)\n"
            result += f"- **Previous**: {previous_value:.2f} {config['unit']} (as of {previous['date']})\n"
        
        # Calculate year-over-year change for inflation indicators
        if config.get("yoy") and len(valid_obs) >= 12:
            year_ago = valid_obs[11] if len(valid_obs) > 11 else valid_obs[-1]
            year_ago_value = float(year_ago["value"])
            yoy_change = ((latest_value - year_ago_value) / year_ago_value) * 100
            result += f"- **Year-over-Year**: {yoy_change:+.2f}%\n"
        
        # Add interpretation
        if indicator_name == "Federal Funds Rate":
            if latest_value > 4.0:
                result += "- **💡 Analysis**: Restrictive monetary policy stance\n"
            elif latest_value < 2.0:
                result += "- **💡 Analysis**: Accommodative monetary policy stance\n"
            else:
                result += "- **💡 Analysis**: Neutral monetary policy stance\n"
        
        elif "CPI" in indicator_name or "PPI" in indicator_name:
            if len(valid_obs) >= 12:
                if yoy_change > 3.0:
                    result += "- **💡 Analysis**: Above Fed's 2% inflation target\n"
                elif yoy_change < 1.0:
                    result += "- **💡 Analysis**: Below Fed's 2% inflation target\n"
                else:
                    result += "- **💡 Analysis**: Near Fed's 2% inflation target\n"
        
        elif indicator_name == "Unemployment Rate":
            if latest_value < 4.0:
                result += "- **💡 Analysis**: Very low unemployment, tight labor market\n"
            elif latest_value > 6.0:
                result += "- **💡 Analysis**: Elevated unemployment, loose labor market\n"
            else:
                result += "- **💡 Analysis**: Moderate unemployment levels\n"
        
        elif "PMI" in indicator_name:
            if latest_value > 50:
                result += "- **💡 Analysis**: Expanding manufacturing sector\n"
            else:
                result += "- **💡 Analysis**: Contracting manufacturing sector\n"
        
        elif indicator_name == "VIX":
            if latest_value > 30:
                result += "- **💡 Analysis**: High market volatility/fear\n"
            elif latest_value < 15:
                result += "- **💡 Analysis**: Low market volatility/complacency\n"
            else:
                result += "- **💡 Analysis**: Moderate market volatility\n"
        
        result += "\n"
    
    return result


def get_fed_calendar_and_minutes(curr_date: str) -> str:
    """
    Get Federal Reserve meeting calendar and recent minutes
    
    Args:
        curr_date: Current date in YYYY-MM-DD format
        
    Returns:
        Formatted string with Fed calendar information
    """
    result = f"## Federal Reserve Calendar & Policy Updates\n\n"
    
    # Get recent Fed Funds rate data to show policy trajectory
    start_date = (datetime.strptime(curr_date, "%Y-%m-%d") - timedelta(days=365)).strftime("%Y-%m-%d")
    fed_data = get_fred_data("FEDFUNDS", start_date, curr_date)
    
    if "error" not in fed_data:
        observations = fed_data.get("observations", [])
        valid_obs = [obs for obs in observations if obs.get("value") != "."]
        
        if valid_obs and len(valid_obs) >= 2:
            result += "### Recent Federal Funds Rate History\n"
            result += "| Date | Rate (%) | Change |\n"
            result += "|------|----------|--------|\n"
            
            for i, obs in enumerate(valid_obs[:6]):  # Show last 6 observations
                rate = float(obs["value"])
                if i < len(valid_obs) - 1:
                    prev_rate = float(valid_obs[i + 1]["value"])
                    change = rate - prev_rate
                    change_str = f"{change:+.2f}%" if change != 0 else "No change"
                else:
                    change_str = "-"
                
                result += f"| {obs['date']} | {rate:.2f}% | {change_str} |\n"
            
            result += "\n"
    
    # Fed meeting schedule (approximate - would need real Fed calendar API)
    result += "### 2024 FOMC Meeting Schedule\n"
    result += "- **January 30-31**: FOMC Meeting\n"
    result += "- **March 19-20**: FOMC Meeting\n"
    result += "- **April 30-May 1**: FOMC Meeting\n"
    result += "- **June 11-12**: FOMC Meeting\n"
    result += "- **July 30-31**: FOMC Meeting\n"
    result += "- **September 17-18**: FOMC Meeting\n"
    result += "- **October 29-30**: FOMC Meeting\n"
    result += "- **December 17-18**: FOMC Meeting\n\n"
    
    result += "### Key Policy Considerations\n"
    result += "- **Dual Mandate**: Maximum employment and price stability\n"
    result += "- **Inflation Target**: 2% annual PCE inflation\n"
    result += "- **Balance Sheet**: Quantitative tightening operations\n"
    result += "- **Forward Guidance**: Communication of future policy intentions\n\n"
    
    result += "### Recent Economic Projections Summary\n"
    result += "- Monitor Fed dot plot for interest rate projections\n"
    result += "- Watch for changes in economic growth forecasts\n"
    result += "- Track inflation expectations updates\n"
    result += "- Observe unemployment rate projections\n\n"
    
    return result


def get_macro_economic_summary(curr_date: str) -> str:
    """
    Get comprehensive macro economic summary combining economic indicators, yield curves, and Fed data
    
    Args:
        curr_date: Current date in YYYY-MM-DD format
        
    Returns:
        Complete macro economic analysis
    """
    result = f"# Macro Economic Analysis - {curr_date}\n\n"
    
    # Get all components
    indicators_report = get_economic_indicators_report(curr_date)
    yield_curve = get_treasury_yield_curve(curr_date)
    fed_calendar = get_fed_calendar_and_minutes(curr_date)
    
    # Combine all reports
    result += indicators_report + "\n"
    result += yield_curve + "\n"
    result += fed_calendar + "\n"
    
    # Add trading implications
    result += "## Trading Implications\n\n"
    result += "### Interest Rate Environment\n"
    result += "- **Rising Rates**: Favor financials, pressure growth stocks\n"
    result += "- **Falling Rates**: Support growth stocks, pressure financials\n"
    result += "- **Yield Curve**: Inversion signals recession risk\n\n"
    
    result += "### Inflation Impact\n"
    result += "- **High Inflation**: Favor commodities, real assets\n"
    result += "- **Low Inflation**: Support bonds, growth stocks\n"
    result += "- **Deflation Risk**: Flight to quality assets\n\n"
    
    result += "### Economic Growth\n"
    result += "- **Strong Growth**: Favor cyclical sectors\n"
    result += "- **Weak Growth**: Favor defensive sectors\n"
    result += "- **Recession Risk**: Increase cash, quality focus\n\n"
    
    result += "### Market Volatility\n"
    result += "- **High VIX**: Opportunity for contrarian plays\n"
    result += "- **Low VIX**: Risk of complacency\n"
    result += "- **Vol Regime Change**: Adjust position sizing\n\n"
    
    return result 