"""
Approval Modes for SparkNet.

Controls how sparks are approved for sharing:
- MANUAL: Every spark requires explicit user approval (default)
- AUTO_SAFE: Auto-approve if no security warnings detected
- OFFLINE: Never share to network, local storage only
"""

import json
from dataclasses import dataclass, field
from enum import Enum
from pathlib import Path
from typing import Optional, List, Dict, Any

from ..security.scanner import FindingSeverity


class ApprovalMode(Enum):
    """How sparks are approved for sharing."""

    MANUAL = "manual"
    """Every spark requires explicit user approval. Most secure."""

    AUTO_SAFE = "auto_safe"
    """Auto-approve sparks with no security warnings.
    Sparks with any warnings still require manual review."""

    AUTO_LOW = "auto_low"
    """Auto-approve sparks with no HIGH or CRITICAL warnings.
    Only MEDIUM and above require manual review."""

    OFFLINE = "offline"
    """Never share to network. All sparks stay local.
    No approval needed since nothing is shared."""


@dataclass
class ApprovalConfig:
    """Configuration for the approval system."""

    mode: ApprovalMode = ApprovalMode.MANUAL
    """Current approval mode."""

    auto_approve_domains: List[str] = field(default_factory=list)
    """Domains that can be auto-approved (e.g., ['python', 'react'])."""

    never_share_domains: List[str] = field(default_factory=list)
    """Domains that should never be shared (e.g., ['internal', 'proprietary'])."""

    min_confidence_for_auto: float = 0.8
    """Minimum confidence score for auto-approval."""

    require_review_for_types: List[str] = field(default_factory=lambda: [
        "architectural",
        "principle",
    ])
    """Spark types that always require manual review."""

    block_on_severity: FindingSeverity = FindingSeverity.HIGH
    """Auto-block sparks with findings at this severity or higher."""

    # UI preferences
    show_redacted_preview: bool = True
    """Show redacted preview in dashboard."""

    require_confirmation_for_bulk: bool = True
    """Require confirmation for bulk approve/reject."""

    # Audit settings
    keep_history_days: int = 90
    """How long to keep approval history."""

    def to_dict(self) -> Dict[str, Any]:
        return {
            "mode": self.mode.value,
            "auto_approve_domains": self.auto_approve_domains,
            "never_share_domains": self.never_share_domains,
            "min_confidence_for_auto": self.min_confidence_for_auto,
            "require_review_for_types": self.require_review_for_types,
            "block_on_severity": self.block_on_severity.value,
            "show_redacted_preview": self.show_redacted_preview,
            "require_confirmation_for_bulk": self.require_confirmation_for_bulk,
            "keep_history_days": self.keep_history_days,
        }

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "ApprovalConfig":
        return cls(
            mode=ApprovalMode(data.get("mode", "manual")),
            auto_approve_domains=data.get("auto_approve_domains", []),
            never_share_domains=data.get("never_share_domains", []),
            min_confidence_for_auto=data.get("min_confidence_for_auto", 0.8),
            require_review_for_types=data.get("require_review_for_types", ["architectural", "principle"]),
            block_on_severity=FindingSeverity(data.get("block_on_severity", "high")),
            show_redacted_preview=data.get("show_redacted_preview", True),
            require_confirmation_for_bulk=data.get("require_confirmation_for_bulk", True),
            keep_history_days=data.get("keep_history_days", 90),
        )

    def save(self, path: Optional[Path] = None):
        """Save config to file."""
        if path is None:
            path = Path.home() / ".sparknet" / "approval_config.json"
        path.parent.mkdir(parents=True, exist_ok=True)
        with open(path, "w") as f:
            json.dump(self.to_dict(), f, indent=2)

    @classmethod
    def load(cls, path: Optional[Path] = None) -> "ApprovalConfig":
        """Load config from file, or return defaults."""
        if path is None:
            path = Path.home() / ".sparknet" / "approval_config.json"
        try:
            with open(path) as f:
                return cls.from_dict(json.load(f))
        except (FileNotFoundError, json.JSONDecodeError):
            return cls()

    def should_auto_approve(
        self,
        domain: Optional[str],
        spark_type: str,
        confidence: float,
        has_warnings: bool,
        highest_severity: Optional[FindingSeverity],
    ) -> bool:
        """
        Check if a spark should be auto-approved based on config.

        Returns True if should auto-approve, False if needs manual review.
        """
        # Offline mode: nothing is shared, no approval needed
        if self.mode == ApprovalMode.OFFLINE:
            return False  # But we mark as local_only, not approved

        # Manual mode: always requires review
        if self.mode == ApprovalMode.MANUAL:
            return False

        # Check never-share domains
        if domain and domain.lower() in [d.lower() for d in self.never_share_domains]:
            return False

        # Check types that always require review
        if spark_type.lower() in [t.lower() for t in self.require_review_for_types]:
            return False

        # Check confidence threshold
        if confidence < self.min_confidence_for_auto:
            return False

        # AUTO_SAFE: no warnings allowed
        if self.mode == ApprovalMode.AUTO_SAFE:
            return not has_warnings

        # AUTO_LOW: only block on HIGH or CRITICAL
        if self.mode == ApprovalMode.AUTO_LOW:
            if highest_severity and highest_severity in [
                FindingSeverity.CRITICAL,
                FindingSeverity.HIGH
            ]:
                return False
            return True

        return False


# Global config
_config: Optional[ApprovalConfig] = None


def get_approval_config() -> ApprovalConfig:
    """Get the current approval configuration."""
    global _config
    if _config is None:
        _config = ApprovalConfig.load()
    return _config


def set_approval_mode(mode: ApprovalMode) -> ApprovalConfig:
    """
    Set the approval mode.

    Args:
        mode: The new approval mode

    Returns:
        Updated config
    """
    global _config
    config = get_approval_config()
    config.mode = mode
    config.save()
    _config = config
    return config


def set_offline_mode():
    """Set to offline mode (nothing shared)."""
    return set_approval_mode(ApprovalMode.OFFLINE)


def set_manual_mode():
    """Set to manual mode (review everything)."""
    return set_approval_mode(ApprovalMode.MANUAL)


def set_auto_safe_mode():
    """Set to auto-safe mode (auto-approve if no warnings)."""
    return set_approval_mode(ApprovalMode.AUTO_SAFE)
