"""Factor types and data classes for the factor market system.

This module defines the core types used by factors including
factor categories, pricing tiers, and result types.
"""

from abc import ABC
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from typing import Any, Optional

import pandas as pd


class FactorType(str, Enum):
    """Types of trading factors."""

    BUY = "buy"  # Buy signal factor
    SELL = "sell"  # Sell signal factor
    SELECT = "select"  # Stock selection factor


class FactorCategory(str, Enum):
    """Category of factor based on complexity and pricing."""

    BASIC = "basic"  # Free basic factors
    ADVANCED = "advanced"  # Paid advanced factors
    PREMIUM = "premium"  # High-end premium factors


class FactorSignal(str, Enum):
    """Signal generated by a factor."""

    BUY = "buy"
    SELL = "sell"
    HOLD = "hold"
    SELECT = "select"
    SKIP = "skip"


@dataclass
class FactorResult:
    """Result of factor evaluation.

    Attributes:
        signal: The trading signal generated
        confidence: Confidence level (0.0 to 1.0)
        symbol: Trading symbol
        timestamp: Result timestamp
        metadata: Additional factor-specific data
    """

    signal: FactorSignal
    confidence: float
    symbol: str = ""
    timestamp: datetime = field(default_factory=datetime.now)
    metadata: dict[str, Any] = field(default_factory=dict)

    def __post_init__(self) -> None:
        """Validate result parameters."""
        if not 0.0 <= self.confidence <= 1.0:
            raise ValueError("Confidence must be between 0.0 and 1.0")


@dataclass
class FactorContext:
    """Context passed to factor evaluation.

    Attributes:
        symbol: Current trading symbol
        data: Market data (OHLCV DataFrame)
        equity: Current equity value
        positions: Current positions
        market_data: Additional market data
        custom_data: Factor-specific custom data
    """

    symbol: str = ""
    data: pd.DataFrame = field(default_factory=pd.DataFrame)
    equity: float = 0.0
    positions: dict[str, Any] = field(default_factory=dict)
    market_data: dict[str, Any] = field(default_factory=dict)
    custom_data: dict[str, Any] = field(default_factory=dict)


@dataclass
class FactorMetadata:
    """Metadata for a trading factor.

    Attributes:
        name: Factor name
        description: Factor description
        factor_type: Type of factor (buy/sell/select)
        category: Category (basic/advanced/premium)
        price: Price in dollars (0 for free)
        author: Factor creator
        version: Factor version
        tags: List of tags for categorization
        min_data_points: Minimum data points required
        parameters: Default parameters
    """

    name: str
    description: str
    factor_type: FactorType
    category: FactorCategory
    price: float = 0.0
    author: str = "OpenClaw"
    version: str = "1.0.0"
    tags: list[str] = field(default_factory=list)
    min_data_points: int = 20
    parameters: dict[str, Any] = field(default_factory=dict)


@dataclass
class PurchaseRecord:
    """Record of a factor purchase.

    Attributes:
        factor_id: Unique factor identifier
        factor_name: Factor name
        price: Purchase price
        timestamp: Purchase timestamp
        agent_id: Agent who purchased
    """

    factor_id: str
    factor_name: str
    price: float
    timestamp: datetime = field(default_factory=datetime.now)
    agent_id: str = ""


@dataclass
class FactorInventoryItem:
    """Item in an agent's factor inventory.

    Attributes:
        factor_id: Unique factor identifier
        factor_name: Factor name
        purchased_at: Purchase timestamp
        unlocked: Whether factor is unlocked and usable
        usage_count: Number of times used
        last_used: Last usage timestamp
    """

    factor_id: str
    factor_name: str
    purchased_at: datetime = field(default_factory=datetime.now)
    unlocked: bool = True
    usage_count: int = 0
    last_used: Optional[datetime] = None

    def mark_used(self) -> None:
        """Mark factor as used."""
        self.usage_count += 1
        self.last_used = datetime.now()
