"""
Type definitions and data classes for the digit counter package.
"""

from dataclasses import dataclass, asdict
from typing import Union, Dict, Any, Optional, List
from datetime import datetime
import json
from enum import Enum
from decimal import Decimal


class CountingMode(str, Enum):
    """Enumeration of counting modes."""
    TOTAL = "total"
    BEFORE = "before"
    AFTER = "after"
    ALL = "all"

    @classmethod
    def values(cls):
        """Get all valid mode values."""
        return [mode.value for mode in cls]


@dataclass
class DigitCountResult:
    """Data class for digit counting results with metadata."""
    value: Union[int, float, str, Decimal]
    total_digits: int
    before_decimal: Optional[int] = None
    after_decimal: Optional[int] = None
    precision_used: Optional[int] = None
    is_integer: bool = False
    processing_time_ms: float = 0.0
    timestamp: Optional[datetime] = None
    error: Optional[str] = None

    def __post_init__(self):
        if self.timestamp is None:
            self.timestamp = datetime.now()

    def to_dict(self) -> Dict[str, Any]:
        result = asdict(self)
        if self.timestamp:
            result["timestamp"] = self.timestamp.isoformat()
        return result

    def to_json(self, indent: Optional[int] = None) -> str:
        return json.dumps(self.to_dict(), indent=indent)

    def summary(self) -> str:
        if self.error:
            return f"Error: {self.error}"

        parts = [f"Value: {self.value!r}", f"Total digits: {self.total_digits}"]
        if self.before_decimal is not None:
            parts.append(f"Before decimal: {self.before_decimal}")
        if self.after_decimal is not None:
            parts.append(f"After decimal: {self.after_decimal}")
        if self.processing_time_ms:
            parts.append(f"Time: {self.processing_time_ms:.3f}ms")
        return " | ".join(parts)


@dataclass
class BatchResult:
    """Data class for batch processing results."""
    total_items: int
    successful_items: int
    failed_items: int
    total_processing_time_ms: float
    average_time_per_item_ms: float
    results: List[Optional[DigitCountResult]]
    errors: List[Dict[str, Any]]

    def to_dict(self) -> Dict[str, Any]:
        return {
            "total_items": self.total_items,
            "successful_items": self.successful_items,
            "failed_items": self.failed_items,
            "total_processing_time_ms": self.total_processing_time_ms,
            "average_time_per_item_ms": self.average_time_per_item_ms,
            "success_rate": self.success_rate,
        }

    @property
    def success_rate(self) -> float:
        if self.total_items == 0:
            return 0.0
        return (self.successful_items / self.total_items) * 100

    def summary(self) -> str:
        return (
            f"Processed {self.total_items} items | "
            f"Success: {self.successful_items} | "
            f"Failed: {self.failed_items} | "
            f"Success rate: {self.success_rate:.1f}% | "
            f"Avg time: {self.average_time_per_item_ms:.3f}ms"
        )


class LogLevel(str, Enum):
    """Enumeration of log levels."""
    DEBUG = "DEBUG"
    INFO = "INFO"
    WARNING = "WARNING"
    ERROR = "ERROR"
    CRITICAL = "CRITICAL"
