"""
Legacy plaintext file backend.

Read-only backend for backward compatibility with existing ~/.g_gremlin/*.json files.
This backend only reads existing files; it never writes.
Migration to keychain should be done via `g-gremlin auth migrate`.

Supports all existing credential storage patterns in g-gremlin.
"""

from __future__ import annotations

import json
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple

from g_gremlin.credentials.models import SecretSource, SecretValue
from g_gremlin.paths import resolve_gremlin_home


class LegacyFileBackend:
    """
    Read-only backend for legacy plaintext JSON config files.

    This backend only reads existing files; it never writes.
    Migration to keychain should be done via `g-gremlin auth migrate`.
    """

    CONFIG_DIR = resolve_gremlin_home()

    # Map (integration, key) -> (filename, json_key)
    # This maps all existing credential patterns in the codebase
    LEGACY_MAPPINGS: Dict[Tuple[str, str], Tuple[str, str]] = {
        # Apollo - from apollo.py
        ("apollo", "api_key"): ("config.json", "apollo_api_key"),
        # Amplemarket - from amplemarket.py
        ("amplemarket", "api_key"): ("amplemarket.json", "api_key"),
        # Outreach - from outreach.py
        ("outreach", "client_id"): ("outreach.json", "client_id"),
        ("outreach", "client_secret"): ("outreach.json", "client_secret"),
        ("outreach", "refresh_token"): ("outreach.json", "refresh_token"),
        ("outreach", "access_token"): ("outreach.json", "access_token"),
        ("outreach", "token_expires_at"): ("outreach.json", "token_expires_at"),
        # ZoomInfo - from zoominfo.py
        ("zoominfo", "client_id"): ("config.json", "zoominfo_client_id"),
        ("zoominfo", "client_secret"): ("config.json", "zoominfo_client_secret"),
        ("zoominfo", "access_token"): ("config.json", "zoominfo_access_token"),
        ("zoominfo", "refresh_token"): ("config.json", "zoominfo_refresh_token"),
        ("zoominfo", "token_expires_at"): ("config.json", "zoominfo_token_expires_at"),
        # HubSpot - from hubspot.py
        ("hubspot", "access_token"): ("hubspot.json", "access_token"),
        ("hubspot", "api_version"): ("hubspot.json", "api_version"),
        # Salesforce - from sfdc.py
        ("salesforce", "org_alias"): ("sfdc.json", "org_alias"),
        ("salesforce", "instance_url"): ("sfdc.json", "instance_url"),
        ("salesforce", "access_token"): ("sfdc.json", "access_token"),
        ("salesforce", "refresh_token"): ("sfdc.json", "refresh_token"),
        ("salesforce", "client_id"): ("sfdc.json", "client_id"),
        ("salesforce", "client_secret"): ("sfdc.json", "client_secret"),
        ("salesforce", "username"): ("sfdc.json", "username"),
        ("salesforce", "password"): ("sfdc.json", "password"),
        ("salesforce", "security_token"): ("sfdc.json", "security_token"),
        # Dynamics 365 - from dynamics.py / dynamics_dataverse_mcp.py
        ("dynamics", "environment_url"): ("dynamics.json", "environment_url"),
        ("dynamics", "tenant_id"): ("dynamics.json", "tenant_id"),
        ("dynamics", "client_id"): ("dynamics.json", "client_id"),
        ("dynamics", "client_secret"): ("dynamics.json", "client_secret"),
        ("dynamics", "default_environment"): ("dynamics.json", "default_environment"),
        # Zendesk - from zendesk.py
        ("zendesk", "subdomain"): ("zendesk.json", "subdomain"),
        ("zendesk", "email"): ("zendesk.json", "email"),
        ("zendesk", "api_token"): ("zendesk.json", "api_token"),
        # Apify - from apify.py
        ("apify", "api_token"): ("apify.json", "api_token"),
        # FoundryGraph - from foundrygraph.py
        ("foundrygraph", "api_token"): ("foundrygraph.json", "api_token"),
        ("foundrygraph", "api_base"): ("foundrygraph.json", "api_base"),
    }

    def __init__(self) -> None:
        self._cache: Dict[str, Dict[str, Any]] = {}

    @property
    def source(self) -> SecretSource:
        return SecretSource.LEGACY_FILE

    @property
    def is_available(self) -> bool:
        return True  # Always available for reading

    @property
    def is_read_only(self) -> bool:
        return True  # Never write to plaintext files

    def _load_file(self, filename: str) -> Dict[str, Any]:
        """Load and cache a config file."""
        if filename in self._cache:
            return self._cache[filename]

        path = self.CONFIG_DIR / filename
        if not path.exists():
            return {}

        try:
            data = json.loads(path.read_text(encoding="utf-8"))
            self._cache[filename] = data
            return data
        except Exception:
            return {}

    def get_secret(
        self,
        integration: str,
        key: str,
        profile: str = "default",
    ) -> Optional[SecretValue]:
        """
        Get secret from legacy JSON file.

        Supports both the original flat format (``{"access_token": "..."}``)
        and the newer ProfileStore nested format
        (``{"profiles": {"default": {"access_token": "..."}}}``) so that
        credentials written by ``hubspot connect`` (which uses ProfileStore)
        are discoverable via this backend.
        """
        mapping = self.LEGACY_MAPPINGS.get((integration, key))
        if mapping is None:
            return None

        filename, json_key = mapping
        data = self._load_file(filename)

        # Try flat (legacy) format first
        value = data.get(json_key)

        # Fallback: try ProfileStore nested format
        if value is None:
            value = data.get("profiles", {}).get(profile, {}).get(json_key)

        if value is None:
            return None

        # Handle both string and non-string values
        str_value = str(value).strip() if isinstance(value, str) else str(value)
        if str_value == "":
            return None

        return SecretValue(
            value=str_value,
            source=SecretSource.LEGACY_FILE,
            integration=integration,
            key=key,
            profile=profile,
            metadata={"file": filename, "json_key": json_key},
        )

    def set_secret(
        self,
        integration: str,
        key: str,
        value: str,
        profile: str = "default",
    ) -> None:
        """Not supported - legacy file backend is read-only."""
        raise NotImplementedError(
            "Legacy file backend is read-only. "
            "Use keychain storage: g-gremlin auth set"
        )

    def delete_secret(
        self,
        integration: str,
        key: str,
        profile: str = "default",
    ) -> bool:
        """Not supported - legacy file backend is read-only."""
        return False

    def list_secrets(
        self,
        integration: Optional[str] = None,
        profile: str = "default",
    ) -> List[Tuple[str, str]]:
        """List secrets that exist in legacy files."""
        found: List[Tuple[str, str]] = []

        for (integ, key), (filename, json_key) in self.LEGACY_MAPPINGS.items():
            if integration and integ != integration:
                continue
            data = self._load_file(filename)
            if data.get(json_key):
                found.append((integ, key))

        return found

    def get_migratable_secrets(self) -> List[Tuple[str, str, str]]:
        """
        Get all secrets that can be migrated to keychain.

        Returns list of (integration, key, value).
        Used by `g-gremlin auth migrate`.
        """
        secrets: List[Tuple[str, str, str]] = []

        for (integ, key), (filename, json_key) in self.LEGACY_MAPPINGS.items():
            data = self._load_file(filename)
            value = data.get(json_key)
            if value:
                str_value = str(value).strip() if isinstance(value, str) else str(value)
                if str_value:
                    secrets.append((integ, key, str_value))

        return secrets

    def get_legacy_file_paths(self) -> List[Path]:
        """
        Get paths to all legacy files that contain secrets.

        Used by migration to track which files were processed.
        """
        files: set[Path] = set()

        for (integ, key), (filename, json_key) in self.LEGACY_MAPPINGS.items():
            data = self._load_file(filename)
            if data.get(json_key):
                files.add(self.CONFIG_DIR / filename)

        return sorted(files)

    def clear_cache(self) -> None:
        """Clear the file cache (useful after external modifications)."""
        self._cache.clear()
