"""FRED (Federal Reserve Economic Data) data fetching.

Provides the FREDData class for fetching Producer Price Index data
from the FRED API and computing deflators.

Requires the 'fred' extra: pip install atlas-common-data[fred]
Requires FRED_API_KEY environment variable to be set.
"""

import os
import pandas as pd
from fredapi import Fred

FRED_INDEX_MONTH = 12


class FREDData:
    """Fetch and process FRED economic data.

    Primarily used to compute a Producer Price Index (PPI) deflator
    for adjusting trade values to constant dollars.

    Example:
        fred = FREDData()
        df = fred.get_inflation_index(base_year=2023)
    """

    SERIES_PPIIDC = "PPIIDC"

    def __init__(self, api_key=None):
        """Initialize FREDData.

        Args:
            api_key: FRED API key. If None, reads from FRED_API_KEY env var.
        """
        self.api_key = api_key or os.environ.get("FRED_API_KEY")

    def get_inflation_index(self, base_year, month=FRED_INDEX_MONTH):
        """Fetch PPI Industrial Commodities index and compute deflator.

        Args:
            base_year: Year to normalise the deflator to (deflator = 1.0 at
                this year). This is distinct from the latest data year used by
                IMFData/WDIData — it controls the scale of the deflator, not
                the range of data fetched.
            month: Month to use for the annual value (default: 12 = December).

        Returns:
            DataFrame with columns: year, ppiidc_index, atlas_base_year, deflator

        Raises:
            ValueError: If no API key is configured or base_year has no data
            RuntimeError: If the FRED API call fails
        """
        if not self.api_key:
            raise ValueError(
                "FRED API key is required. Pass api_key= to FREDData() "
                "or set the FRED_API_KEY environment variable."
            )

        try:
            fred = Fred(api_key=self.api_key)
            series = fred.get_series_latest_release(self.SERIES_PPIIDC)
        except Exception as e:
            raise RuntimeError(
                f"Failed to fetch FRED {self.SERIES_PPIIDC} series: {e}"
            ) from e

        series.name = "ppiidc_index"
        series.index.name = "YY-MM-DD"

        df = series.reset_index()
        df = df[df["YY-MM-DD"].dt.month == month]
        df["year"] = df["YY-MM-DD"].dt.year

        base_rows = df.loc[df["year"] == base_year, "ppiidc_index"]
        if len(base_rows) == 0:
            available = sorted(df["year"].unique().tolist())
            raise ValueError(
                f"base_year {base_year} not found in FRED data. "
                f"Available years: {available}"
            )
        base = base_rows.iloc[0]
        df["atlas_base_year"] = base_year
        df["deflator"] = df["ppiidc_index"] / base

        df = df.drop(columns=["YY-MM-DD"])
        return df

    def get_fred_data(self, base_year):
        """Fetch FRED PPIIDC deflator — matches schema of fred_ppiidc.csv.

        This is the primary method whose output matches the legacy CSV file.
        Equivalent to get_inflation_index().

        Args:
            base_year: Year to normalise the deflator to (deflator = 1.0 at
                this year). Typically set to the same value as end_year on
                IMFData/WDIData, but it is a separate concept — it controls
                the scale of the deflator, not the range of economic data.

        Returns:
            DataFrame with columns: year, ppiidc_index, atlas_base_year, deflator
        """
        return self.get_inflation_index(base_year=base_year)

    @classmethod
    def list_available_series(cls):
        """List available FRED series this class supports.

        Returns:
            dict mapping series ID to description.
        """
        return {
            cls.SERIES_PPIIDC: "Producer Price Index by Commodity: Industrial Commodities",
        }
