"""
ID Wispera OpenClaw Provider
Specialized scanner for OpenClaw credential locations
"""

import json
import os
from dataclasses import dataclass, field
from pathlib import Path
from typing import Optional

from id_wispera.types import CredentialType, VisaType, RiskLevel


@dataclass
class OpenClawCredential:
    """A credential discovered in OpenClaw"""
    name: str
    credential_type: CredentialType
    visa_type: VisaType
    risk_level: RiskLevel
    file_path: str
    raw_value: str
    metadata: dict = field(default_factory=dict)


@dataclass
class OpenClawScanResult:
    """Result of scanning OpenClaw installation"""
    installed: bool
    install_path: str
    credentials: list[OpenClawCredential] = field(default_factory=list)
    permission_warnings: list[str] = field(default_factory=list)
    unreadable_paths: list[str] = field(default_factory=list)


def scan_openclaw() -> OpenClawScanResult:
    """
    Scan OpenClaw installation for credentials.

    Returns:
        OpenClawScanResult with all discovered credentials
    """
    openclaw_path = Path.home() / ".openclaw"

    result = OpenClawScanResult(
        installed=openclaw_path.exists(),
        install_path=str(openclaw_path),
    )

    if not result.installed:
        return result

    # Scan WhatsApp credentials
    _scan_whatsapp(openclaw_path, result)

    # Scan auth profiles (LLM API keys)
    _scan_auth_profiles(openclaw_path, result)

    # Scan OAuth tokens
    _scan_oauth_tokens(openclaw_path, result)

    # Scan config for channel tokens
    _scan_config(openclaw_path, result)

    # Scan allowlists
    _scan_allowlists(openclaw_path, result)

    return result


def _scan_whatsapp(base_path: Path, result: OpenClawScanResult) -> None:
    """Scan WhatsApp credentials"""
    whatsapp_path = base_path / "credentials" / "whatsapp"

    if not whatsapp_path.exists():
        return

    try:
        for account_dir in whatsapp_path.iterdir():
            if not account_dir.is_dir():
                continue

            creds_path = account_dir / "creds.json"
            if not creds_path.exists():
                continue

            try:
                content = creds_path.read_text()
                data = json.loads(content)

                result.credentials.append(OpenClawCredential(
                    name=f"WhatsApp Session ({account_dir.name})",
                    credential_type=CredentialType.SESSION_KEYS,
                    visa_type=VisaType.ACCESS,
                    risk_level=RiskLevel.HIGH,
                    file_path=str(creds_path),
                    raw_value=content,
                    metadata={
                        "account_id": account_dir.name,
                        "bot_name": data.get("me", {}).get("name"),
                    },
                ))
            except PermissionError:
                result.unreadable_paths.append(str(creds_path))
            except (json.JSONDecodeError, Exception):
                pass
    except PermissionError:
        result.unreadable_paths.append(str(whatsapp_path))


def _scan_auth_profiles(base_path: Path, result: OpenClawScanResult) -> None:
    """Scan agent auth profiles for LLM API keys"""
    agents_path = base_path / "agents"

    if not agents_path.exists():
        return

    try:
        for agent_dir in agents_path.iterdir():
            if not agent_dir.is_dir():
                continue

            auth_path = agent_dir / "agent" / "auth-profiles.json"
            if not auth_path.exists():
                continue

            try:
                content = auth_path.read_text()
                data = json.loads(content)

                for provider, profile in data.items():
                    if profile.get("type") == "api-key" and profile.get("key"):
                        key = profile["key"]
                        preview = f"{key[:10]}...{key[-4:]}" if len(key) > 14 else key[:4] + "..."

                        result.credentials.append(OpenClawCredential(
                            name=f"{provider.capitalize()} API Key ({preview})",
                            credential_type=CredentialType.API_KEY,
                            visa_type=VisaType.PRIVILEGE,
                            risk_level=RiskLevel.CRITICAL,
                            file_path=str(auth_path),
                            raw_value=key,
                            metadata={
                                "provider": provider,
                                "model": profile.get("model"),
                                "agent_id": agent_dir.name,
                            },
                        ))
            except PermissionError:
                result.unreadable_paths.append(str(auth_path))
            except (json.JSONDecodeError, Exception):
                pass
    except PermissionError:
        result.unreadable_paths.append(str(agents_path))


def _scan_oauth_tokens(base_path: Path, result: OpenClawScanResult) -> None:
    """Scan OAuth tokens"""
    oauth_path = base_path / "credentials" / "oauth.json"

    if not oauth_path.exists():
        return

    try:
        content = oauth_path.read_text()
        data = json.loads(content)

        for provider, tokens in data.items():
            if tokens.get("access_token"):
                token = tokens["access_token"]
                preview = f"{token[:10]}..."

                result.credentials.append(OpenClawCredential(
                    name=f"{provider.capitalize()} OAuth ({preview})",
                    credential_type=CredentialType.OAUTH_TOKEN,
                    visa_type=VisaType.ACCESS,
                    risk_level=RiskLevel.MEDIUM,
                    file_path=str(oauth_path),
                    raw_value=token,
                    metadata={
                        "provider": provider,
                        "has_refresh_token": "refresh_token" in tokens,
                    },
                ))
    except PermissionError:
        result.unreadable_paths.append(str(oauth_path))
    except (json.JSONDecodeError, Exception):
        pass


def _scan_config(base_path: Path, result: OpenClawScanResult) -> None:
    """Scan openclaw.json for channel tokens"""
    config_path = base_path / "openclaw.json"

    if not config_path.exists():
        return

    try:
        content = config_path.read_text()
        data = json.loads(content)

        channels = data.get("channels", {})

        # Telegram
        if channels.get("telegram", {}).get("token"):
            token = channels["telegram"]["token"]
            result.credentials.append(OpenClawCredential(
                name=f"Telegram Bot Token",
                credential_type=CredentialType.BOT_TOKEN,
                visa_type=VisaType.ACCESS,
                risk_level=RiskLevel.HIGH,
                file_path=str(config_path),
                raw_value=token,
                metadata={"channel": "telegram"},
            ))

        # Slack
        if channels.get("slack", {}).get("botToken"):
            token = channels["slack"]["botToken"]
            result.credentials.append(OpenClawCredential(
                name=f"Slack Bot Token",
                credential_type=CredentialType.BOT_TOKEN,
                visa_type=VisaType.ACCESS,
                risk_level=RiskLevel.HIGH,
                file_path=str(config_path),
                raw_value=token,
                metadata={"channel": "slack"},
            ))

        # Discord
        if channels.get("discord", {}).get("token"):
            token = channels["discord"]["token"]
            result.credentials.append(OpenClawCredential(
                name=f"Discord Bot Token",
                credential_type=CredentialType.BOT_TOKEN,
                visa_type=VisaType.ACCESS,
                risk_level=RiskLevel.HIGH,
                file_path=str(config_path),
                raw_value=token,
                metadata={"channel": "discord"},
            ))

        # Gateway token
        if data.get("gateway", {}).get("token"):
            token = data["gateway"]["token"]
            result.credentials.append(OpenClawCredential(
                name=f"Gateway Token",
                credential_type=CredentialType.API_KEY,
                visa_type=VisaType.PRIVILEGE,
                risk_level=RiskLevel.HIGH,
                file_path=str(config_path),
                raw_value=token,
                metadata={"gateway_port": data["gateway"].get("port")},
            ))
    except PermissionError:
        result.unreadable_paths.append(str(config_path))
    except (json.JSONDecodeError, Exception):
        pass


def _scan_allowlists(base_path: Path, result: OpenClawScanResult) -> None:
    """Scan channel allowlists"""
    creds_path = base_path / "credentials"

    if not creds_path.exists():
        return

    try:
        for file_path in creds_path.iterdir():
            if not file_path.name.endswith("-allowFrom.json"):
                continue

            try:
                content = file_path.read_text()
                data = json.loads(content)
                channel = file_path.name.replace("-allowFrom.json", "")
                paired_count = len(data)

                result.credentials.append(OpenClawCredential(
                    name=f"Pairing: {channel} ({paired_count} users)",
                    credential_type=CredentialType.CUSTOM,
                    visa_type=VisaType.ACCESS,
                    risk_level=RiskLevel.LOW,
                    file_path=str(file_path),
                    raw_value=content,
                    metadata={
                        "channel": channel,
                        "paired_count": paired_count,
                    },
                ))
            except PermissionError:
                result.unreadable_paths.append(str(file_path))
            except (json.JSONDecodeError, Exception):
                pass
    except PermissionError:
        result.unreadable_paths.append(str(creds_path))
