"""
Base parser interface for factor mining results
"""

from abc import ABC, abstractmethod
from typing import List, Dict, Any, Optional
from pathlib import Path
import json

from ..core.factor import MinedFactor
from ..core.config import AssetType, FactorType


class BaseFactorParser(ABC):
    """
    Abstract base class for factor mining result parsers.

    Each parser handles results from a specific framework (gpfactor, masfactorMiner).
    """

    def __init__(
        self,
        asset_type: AssetType = AssetType.STOCK,
        factor_type: FactorType = FactorType.DAILY
    ):
        self.asset_type = asset_type
        self.factor_type = factor_type

    @property
    @abstractmethod
    def framework_name(self) -> str:
        """Return the name of the framework this parser handles"""
        pass

    @abstractmethod
    def parse_factor(self, data: Dict[str, Any]) -> MinedFactor:
        """
        Parse a single factor from its data dictionary.

        Args:
            data: Dictionary containing factor data

        Returns:
            MinedFactor instance
        """
        pass

    @abstractmethod
    def parse_file_content(self, content: Dict[str, Any] | List[Dict[str, Any]]) -> List[MinedFactor]:
        """
        Parse factors from file content.

        Args:
            content: Parsed JSON content (dict or list)

        Returns:
            List of MinedFactor instances
        """
        pass

    def parse_file(self, file_path: str | Path) -> List[MinedFactor]:
        """
        Parse factors from a JSON file.

        Args:
            file_path: Path to the JSON file

        Returns:
            List of MinedFactor instances
        """
        file_path = Path(file_path)
        if not file_path.exists():
            raise FileNotFoundError(f"Factor file not found: {file_path}")

        with open(file_path, 'r', encoding='utf-8') as f:
            content = json.load(f)

        return self.parse_file_content(content)

    def filter_valid_factors(
        self,
        factors: List[MinedFactor],
        min_coverage: Optional[float] = None,
        min_ic: Optional[float] = None,
        max_factors: Optional[int] = None
    ) -> List[MinedFactor]:
        """
        Filter factors based on quality criteria.

        Args:
            factors: List of MinedFactor instances
            min_coverage: Minimum factor coverage (0-1)
            min_ic: Minimum absolute IC mean
            max_factors: Maximum number of factors to return

        Returns:
            Filtered list of MinedFactor instances
        """
        filtered = []

        for factor in factors:
            # Check coverage
            if min_coverage is not None:
                coverage = factor.get_metric("factor_coverage") or factor.get_metric("coverage")
                if coverage is not None and coverage < min_coverage:
                    continue

            # Check IC
            if min_ic is not None:
                ic_mean = factor.get_metric("ic_mean") or factor.get_metric("mean_ic")
                if ic_mean is not None and abs(ic_mean) < min_ic:
                    continue

            filtered.append(factor)

        # Limit number of factors
        if max_factors is not None:
            filtered = filtered[:max_factors]

        return filtered

    def get_summary(self, factors: List[MinedFactor]) -> Dict[str, Any]:
        """
        Get summary statistics for a list of factors.

        Args:
            factors: List of MinedFactor instances

        Returns:
            Dictionary with summary statistics
        """
        if not factors:
            return {"count": 0}

        ic_means = []
        ic_irs = []

        for factor in factors:
            ic = factor.get_metric("ic_mean") or factor.get_metric("mean_ic")
            if ic is not None:
                ic_means.append(ic)

            icir = factor.get_metric("ic_ir") or factor.get_metric("icir")
            if icir is not None:
                ic_irs.append(icir)

        summary = {
            "count": len(factors),
            "framework": self.framework_name,
        }

        if ic_means:
            summary["avg_ic_mean"] = sum(ic_means) / len(ic_means)
            summary["max_abs_ic_mean"] = max(abs(ic) for ic in ic_means)

        if ic_irs:
            summary["avg_icir"] = sum(ic_irs) / len(ic_irs)
            summary["max_abs_icir"] = max(abs(ir) for ir in ic_irs)

        return summary
