"""
Webhook profile management.

Profiles are stored as JSON in:
- .g_gremlin/webhooks/{name}.json (project-level, takes precedence)
- ~/.g_gremlin/webhooks/{name}.json (user-level)
"""

from __future__ import annotations

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

from g_gremlin.paths import gremlin_path


# Profile search order (project first, then user)
PROFILE_DIRS = [
    Path(".g_gremlin/webhooks"),
    gremlin_path("webhooks"),
]


@dataclass
class WebhookProfile:
    """
    Saved webhook configuration for reuse.

    Profiles store the target URL, format preference, and optional headers.
    """

    name: str
    url: str
    format: Optional[str] = None  # flat|wrapped|generic
    headers: Dict[str, str] = field(default_factory=dict)
    timeout: float = 10.0
    max_retries: int = 3

    def to_dict(self, include_url: bool = False) -> Dict[str, Any]:
        """
        Serialize profile to dict.

        Args:
            include_url: If False (default), URL is masked for safe logging/display.
                         Only set True for internal use (saving to disk).
        """
        from g_gremlin.webhook_out.envelope import mask_url

        return {
            "name": self.name,
            "url": self.url if include_url else mask_url(self.url),
            "format": self.format,
            "headers": {k: "[REDACTED]" for k in self.headers} if self.headers else {},
            "timeout": self.timeout,
            "max_retries": self.max_retries,
        }

    def to_dict_for_storage(self) -> Dict[str, Any]:
        """Serialize profile for disk storage (includes sensitive data)."""
        return {
            "name": self.name,
            "url": self.url,
            "format": self.format,
            "headers": self.headers,
            "timeout": self.timeout,
            "max_retries": self.max_retries,
        }

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "WebhookProfile":
        """Deserialize profile from dict."""
        return cls(
            name=data.get("name", ""),
            url=data.get("url", ""),
            format=data.get("format"),
            headers=data.get("headers", {}),
            timeout=data.get("timeout", 10.0),
            max_retries=data.get("max_retries", 3),
        )


def profile_get(name: str) -> Optional[WebhookProfile]:
    """
    Load webhook profile by name.

    Searches project-level first, then user-level.
    """
    for profile_dir in PROFILE_DIRS:
        profile_path = profile_dir / f"{name}.json"
        if profile_path.exists():
            try:
                with profile_path.open("r", encoding="utf-8") as f:
                    data = json.load(f)
                    data["name"] = name  # Ensure name matches filename
                    return WebhookProfile.from_dict(data)
            except (json.JSONDecodeError, IOError):
                continue
    return None


def profile_set(
    profile: WebhookProfile,
    project_level: bool = True,
) -> Path:
    """
    Save webhook profile to disk.

    Args:
        profile: WebhookProfile to save
        project_level: If True, save to .g_gremlin/webhooks/; else ~/.g_gremlin/webhooks/

    Returns:
        Path where profile was saved
    """
    target_dir = PROFILE_DIRS[0] if project_level else PROFILE_DIRS[1]
    target_dir.mkdir(parents=True, exist_ok=True)

    profile_path = target_dir / f"{profile.name}.json"
    with profile_path.open("w", encoding="utf-8") as f:
        # Use to_dict_for_storage() to include full URL when saving
        json.dump(profile.to_dict_for_storage(), f, indent=2)

    return profile_path


def profile_list() -> List[WebhookProfile]:
    """
    List all available webhook profiles.

    Returns profiles from both project and user directories.
    Project-level profiles take precedence over user-level.
    """
    profiles: Dict[str, WebhookProfile] = {}

    # Reverse order so project-level overrides user-level
    for profile_dir in reversed(PROFILE_DIRS):
        if not profile_dir.exists():
            continue
        for profile_path in profile_dir.glob("*.json"):
            name = profile_path.stem
            try:
                with profile_path.open("r", encoding="utf-8") as f:
                    data = json.load(f)
                    data["name"] = name
                    profiles[name] = WebhookProfile.from_dict(data)
            except (json.JSONDecodeError, IOError):
                continue  # Skip malformed profiles

    return sorted(profiles.values(), key=lambda p: p.name)


def profile_delete(name: str) -> bool:
    """
    Delete webhook profile by name.

    Deletes from project-level first if exists, then user-level.

    Returns:
        True if a profile was deleted, False otherwise
    """
    for profile_dir in PROFILE_DIRS:
        profile_path = profile_dir / f"{name}.json"
        if profile_path.exists():
            try:
                profile_path.unlink()
                return True
            except IOError:
                continue
    return False
