# Familiar - Self-Hosted AI Companion Platform
# Copyright (c) 2026 George Scott Foley
# ORCID: 0009-0006-4957-0540
# Email: Georgescottfoley@proton.me
# Licensed under the MIT License - see LICENSE file for details

"""
Familiar Result Types

Standardized result types for consistent error handling across the application.

Usage:
    from familiar.core.result import Result, Ok, Err

    def my_function() -> Result[str]:
        if success:
            return Ok("data")
        else:
            return Err("Something went wrong")

    result = my_function()
    if result.success:
        print(result.data)
    else:
        print(f"Error: {result.error}")
"""

from dataclasses import dataclass, field
from typing import Any, Generic, Optional, TypeVar, cast

T = TypeVar("T")


@dataclass
class Result(Generic[T]):
    """
    A result type that can represent either success or failure.

    Attributes:
        success: Whether the operation succeeded
        data: The result data (if successful)
        error: Error message (if failed)
        details: Additional details/metadata
    """

    success: bool
    data: Optional[T] = None
    error: Optional[str] = None
    details: dict[str, Any] = field(default_factory=dict)

    def __bool__(self) -> bool:
        """Allow using Result in boolean context."""
        return self.success

    def unwrap(self) -> T:
        """
        Get the data, raising if this is an error result.

        Raises:
            ValueError: If this is an error result
        """
        if not self.success:
            raise ValueError(self.error or "Operation failed")
        # Type narrowing: if success is True, data should be set
        return cast(T, self.data)

    def unwrap_or(self, default: T) -> T:
        """Get the data or return default if error."""
        if self.success and self.data is not None:
            return self.data
        return default

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary for JSON serialization."""
        result: dict[str, Any] = {"success": self.success}
        if self.success:
            result["data"] = self.data
        else:
            result["error"] = self.error
        if self.details:
            result["details"] = self.details
        return result

    def to_string(self) -> str:
        """Convert to user-friendly string."""
        if self.success:
            return str(self.data) if self.data else "✓ Success"
        else:
            return f"Error: {self.error}"


def Ok(data: Optional[T] = None, **details: Any) -> Result[T]:
    """Create a successful result."""
    return Result(success=True, data=data, details=details)


def Err(error: str, **details: Any) -> Result[Any]:
    """Create an error result."""
    return Result(success=False, error=error, details=details)


# Common result types
StringResult = Result[str]
DictResult = Result[dict[str, Any]]
ListResult = Result[list[Any]]


# Conversion helpers for backwards compatibility
def result_to_string(result: Result[Any]) -> str:
    """Convert Result to the old string format for tool handlers."""
    return result.to_string()


def string_to_result(s: str) -> Result[str]:
    """Convert old string format to Result."""
    if s.startswith("Error:") or s.startswith("❌"):
        return Err(s.replace("Error:", "").replace("❌", "").strip())
    return Ok(s)
