"""
Core data models for credential management.

Defines SecretValue, IntegrationStatus, IntegrationSpec, and the INTEGRATION_REGISTRY.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from datetime import datetime, timezone
from enum import Enum
from typing import Any, Dict, List, Optional


class SecretSource(str, Enum):
    """Where the secret was resolved from."""
    CLI_FLAG = "cli_flag"
    ENV_VAR = "env_var"
    KEYCHAIN = "keychain"
    PLATFORM = "platform"
    LEGACY_FILE = "legacy_file"
    PLUGIN = "plugin"
    SAAS = "saas"  # Server-side storage for BYO Provider Locker (Unleashed tier)
    NOT_FOUND = "not_found"


@dataclass
class SecretValue:
    """
    A secret value with metadata about its source and freshness.

    Never serialize the `value` field to logs or JSON output.
    """
    value: str
    source: SecretSource
    integration: str
    key: str
    profile: str = "default"
    last_rotated: Optional[datetime] = None
    expires_at: Optional[datetime] = None
    metadata: Dict[str, Any] = field(default_factory=dict)

    @property
    def is_expired(self) -> bool:
        if self.expires_at is None:
            return False
        return datetime.now(timezone.utc) > self.expires_at

    @property
    def masked_value(self) -> str:
        """Return masked version for safe display."""
        if len(self.value) <= 8:
            return "*" * len(self.value)
        return self.value[:4] + "*" * (len(self.value) - 8) + self.value[-4:]

    def to_safe_dict(self) -> Dict[str, Any]:
        """Serialize without exposing the actual secret value."""
        return {
            "integration": self.integration,
            "key": self.key,
            "profile": self.profile,
            "source": self.source.value,
            "masked_value": self.masked_value,
            "last_rotated": self.last_rotated.isoformat() if self.last_rotated else None,
            "expires_at": self.expires_at.isoformat() if self.expires_at else None,
            "is_expired": self.is_expired,
        }


@dataclass
class IntegrationStatus:
    """
    Status of a configured integration (metadata only, no secrets).
    """
    integration: str
    configured: bool
    source: SecretSource
    profile: str = "default"
    keys_present: List[str] = field(default_factory=list)
    keys_missing: List[str] = field(default_factory=list)
    last_validated: Optional[datetime] = None
    validation_error: Optional[str] = None
    is_plaintext: bool = False  # True if stored in legacy file

    @property
    def status(self) -> str:
        if not self.configured:
            return "not_configured"
        if self.keys_missing:
            return "incomplete"
        if self.validation_error:
            return "error"
        if self.is_plaintext:
            return "plaintext_warning"
        return "ok"

    def to_dict(self) -> Dict[str, Any]:
        return {
            "integration": self.integration,
            "status": self.status,
            "configured": self.configured,
            "source": self.source.value if self.configured else None,
            "profile": self.profile,
            "keys_present": self.keys_present,
            "keys_missing": self.keys_missing,
            "is_plaintext": self.is_plaintext,
            "last_validated": self.last_validated.isoformat() if self.last_validated else None,
            "validation_error": self.validation_error,
        }


@dataclass
class IntegrationSpec:
    """
    Defines what keys an integration requires.

    Adding a new integration (e.g., 6sense, Demandbase) requires only:
    1. New IntegrationSpec entry in INTEGRATION_REGISTRY
    2. Env var mapping (via env_var_prefix)
    3. Optional legacy file mapping in backends/legacy_file.py
    """
    name: str
    display_name: str
    required_keys: List[str]
    optional_keys: List[str] = field(default_factory=list)
    legacy_config_path: Optional[str] = None  # Relative to ~/.g_gremlin/
    env_var_prefix: str = ""  # e.g., "APOLLO_" -> APOLLO_API_KEY
    env_var_aliases: Dict[str, List[str]] = field(default_factory=dict)

    def get_env_var_name(self, key: str) -> str:
        """Convert key to environment variable name."""
        if self.env_var_prefix:
            prefix = self.env_var_prefix
        else:
            prefix = f"G_GREMLIN_{self.name.upper()}_"
        return f"{prefix}{key.upper()}"

    def get_env_var_names(self, key: str) -> List[str]:
        """Return the primary env var name plus any compatibility aliases."""
        names = [self.get_env_var_name(key)]
        names.extend(self.env_var_aliases.get(key, []))
        return names

    def get_all_keys(self) -> List[str]:
        """Return all keys (required + optional)."""
        return self.required_keys + self.optional_keys


# Registry of all known integrations
# To add a new integration, simply add a new entry here
INTEGRATION_REGISTRY: Dict[str, IntegrationSpec] = {
    "apollo": IntegrationSpec(
        name="apollo",
        display_name="Apollo.io",
        required_keys=["api_key"],
        legacy_config_path="config.json",
        env_var_prefix="G_GREMLIN_APOLLO_",
    ),
    "zoominfo": IntegrationSpec(
        name="zoominfo",
        display_name="ZoomInfo",
        required_keys=["client_id", "client_secret"],
        optional_keys=["access_token", "refresh_token", "token_expires_at"],
        legacy_config_path="config.json",
        env_var_prefix="G_GREMLIN_ZOOMINFO_",
    ),
    "hubspot": IntegrationSpec(
        name="hubspot",
        display_name="HubSpot",
        required_keys=["access_token"],
        optional_keys=["api_version"],
        legacy_config_path="hubspot.json",
        env_var_prefix="G_GREMLIN_HUBSPOT_",
    ),
    "salesforce": IntegrationSpec(
        name="salesforce",
        display_name="Salesforce",
        required_keys=["org_alias"],
        optional_keys=[
            "instance_url",
            "org_id",
            "token_type",
            "access_token",
            "refresh_token",
            "client_id",
            "client_secret",
            "username",
            "password",
            "security_token",
        ],
        legacy_config_path="sfdc.json",
        env_var_prefix="G_GREMLIN_SFDC_",
    ),
    "docusign": IntegrationSpec(
        name="docusign",
        display_name="DocuSign",
        required_keys=["access_token"],
        optional_keys=["account_id", "base_uri", "auth_base_url"],
        env_var_prefix="G_GREMLIN_DOCUSIGN_",
    ),
    "pandadoc": IntegrationSpec(
        name="pandadoc",
        display_name="PandaDoc",
        required_keys=["api_key"],
        optional_keys=["api_base"],
        env_var_prefix="G_GREMLIN_PANDADOC_",
    ),
    "adobe_sign": IntegrationSpec(
        name="adobe_sign",
        display_name="Adobe Sign",
        required_keys=["access_token"],
        optional_keys=["api_base", "api_access_point"],
        env_var_prefix="G_GREMLIN_ADOBE_SIGN_",
    ),
    "zendesk": IntegrationSpec(
        name="zendesk",
        display_name="Zendesk",
        required_keys=["subdomain", "email", "api_token"],
        legacy_config_path="zendesk.json",
        env_var_prefix="G_GREMLIN_ZENDESK_",
    ),
    "apify": IntegrationSpec(
        name="apify",
        display_name="Apify",
        required_keys=["api_token"],
        legacy_config_path="apify.json",
        env_var_prefix="APIFY_",  # Existing convention
    ),
    "nimbleway": IntegrationSpec(
        name="nimbleway",
        display_name="Nimbleway",
        required_keys=["api_key"],
        optional_keys=["social_auth"],
        legacy_config_path="nimbleway.json",
        env_var_prefix="NIMBLEWAY_",
        env_var_aliases={
            "api_key": ["NIMBLE_API_KEY"],
            "social_auth": ["NIMBLE_SOCIAL_AUTH"],
        },
    ),
    "foundrygraph": IntegrationSpec(
        name="foundrygraph",
        display_name="FoundryGraph",
        required_keys=[],  # api_token optional for local-only mode
        optional_keys=["api_token", "api_base"],
        legacy_config_path="foundrygraph.json",
        env_var_prefix="G_GREMLIN_FG_",
    ),
    "pubsub": IntegrationSpec(
        name="pubsub",
        display_name="Pub/Sub",
        required_keys=["project_id"],
        optional_keys=["credentials_path"],
        env_var_prefix="G_GREMLIN_PUBSUB_",
    ),
    "google": IntegrationSpec(
        name="google",
        display_name="Google Sheets/Drive",
        required_keys=[],  # OAuth handled separately via token.json
        optional_keys=["credentials_path", "sa_key"],
        legacy_config_path="credentials.json",
        env_var_prefix="G_GREMLIN_GOOGLE_",
    ),
    "instantly": IntegrationSpec(
        name="instantly",
        display_name="Instantly.ai",
        required_keys=["api_key"],
        optional_keys=["webhook_secret"],
        env_var_prefix="G_GREMLIN_INSTANTLY_",
    ),
    "smartlead": IntegrationSpec(
        name="smartlead",
        display_name="Smartlead",
        required_keys=["api_key"],
        optional_keys=["webhook_secret"],
        env_var_prefix="G_GREMLIN_SMARTLEAD_",
    ),
    "commonroom": IntegrationSpec(
        name="commonroom",
        display_name="Common Room",
        required_keys=["webhook_secret"],
        optional_keys=["api_key"],
        env_var_prefix="G_GREMLIN_COMMONROOM_",
    ),
    "heyreach": IntegrationSpec(
        name="heyreach",
        display_name="HeyReach",
        required_keys=["api_key"],
        optional_keys=["workspace_id"],
        env_var_prefix="G_GREMLIN_HEYREACH_",
    ),
    "notion": IntegrationSpec(
        name="notion",
        display_name="Notion",
        required_keys=["token"],
        optional_keys=["default_database_id"],
        env_var_prefix="G_GREMLIN_NOTION_",
    ),
    "outline": IntegrationSpec(
        name="outline",
        display_name="Outline",
        required_keys=["api_token", "api_base"],
        optional_keys=["default_collection_id"],
        env_var_prefix="G_GREMLIN_OUTLINE_",
    ),
    "confluence": IntegrationSpec(
        name="confluence",
        display_name="Confluence",
        required_keys=["api_base", "email", "api_token"],
        optional_keys=["default_space_key", "default_parent_id"],
        env_var_prefix="G_GREMLIN_CONFLUENCE_",
    ),
    "pdl": IntegrationSpec(
        name="pdl",
        display_name="People Data Labs",
        required_keys=["api_key"],
        optional_keys=["api_base"],
        env_var_prefix="G_GREMLIN_PDL_",
    ),
    "clearbit": IntegrationSpec(
        name="clearbit",
        display_name="Clearbit",
        required_keys=["api_key"],
        optional_keys=["api_base"],
        env_var_prefix="G_GREMLIN_CLEARBIT_",
    ),
    "justcall": IntegrationSpec(
        name="justcall",
        display_name="JustCall",
        required_keys=["api_key", "api_secret"],
        optional_keys=["api_base"],
        env_var_prefix="G_GREMLIN_JUSTCALL_",
    ),
    "fullenrich": IntegrationSpec(
        name="fullenrich",
        display_name="FullEnrich",
        required_keys=["api_key"],
        optional_keys=[],
        env_var_prefix="G_GREMLIN_FULLENRICH_",
    ),
    "foundrymatch": IntegrationSpec(
        name="foundrymatch",
        display_name="FoundryMatch SaaS",
        required_keys=["api_base", "api_key", "workspace_id"],
        optional_keys=[],
        env_var_prefix="G_GREMLIN_FM_",
    ),
    "amplemarket": IntegrationSpec(
        name="amplemarket",
        display_name="Amplemarket",
        required_keys=["api_key"],
        optional_keys=[],
        legacy_config_path="amplemarket.json",
    ),
    "outreach": IntegrationSpec(
        name="outreach",
        display_name="Outreach.io",
        required_keys=["client_id", "client_secret", "refresh_token"],
        optional_keys=["access_token", "token_expires_at"],
        env_var_prefix="G_GREMLIN_OUTREACH_",
    ),
    "tableau": IntegrationSpec(
        name="tableau",
        display_name="Tableau Cloud",
        required_keys=["site_url", "access_token", "token_name"],
        optional_keys=["site_name", "api_version"],
        env_var_prefix="G_GREMLIN_TABLEAU_",
    ),
    "looker": IntegrationSpec(
        name="looker",
        display_name="Looker",
        required_keys=["base_url", "client_id", "client_secret"],
        optional_keys=["verify_ssl", "api_version"],
        env_var_prefix="G_GREMLIN_LOOKER_",
    ),
    "dynamics": IntegrationSpec(
        name="dynamics",
        display_name="Dynamics 365 / Power Platform",
        required_keys=["environment_url"],
        optional_keys=[
            "tenant_id",
            "client_id",
            "client_secret",
            "pac_path",
            "default_environment",
        ],
        legacy_config_path="dynamics.json",
        env_var_prefix="G_GREMLIN_DYNAMICS_",
    ),
}
