# app/services/letzshop/credentials_service.py
"""
Letzshop credentials management service.

Handles secure storage and retrieval of per-store Letzshop API credentials.
"""

import logging
from datetime import UTC, datetime

from sqlalchemy.orm import Session

from app.modules.marketplace.models import StoreLetzshopCredentials
from app.utils.encryption import decrypt_value, encrypt_value, mask_api_key

from .client_service import LetzshopClient

logger = logging.getLogger(__name__)

# Default Letzshop GraphQL endpoint
DEFAULT_ENDPOINT = "https://letzshop.lu/graphql"


class CredentialsError(Exception):
    """Base exception for credentials errors."""


class CredentialsNotFoundError(CredentialsError):
    """Raised when credentials are not found for a store."""


class LetzshopCredentialsService:
    """
    Service for managing Letzshop API credentials.

    Provides secure storage and retrieval of encrypted API keys,
    connection testing, and sync status updates.
    """

    def __init__(self, db: Session):
        """
        Initialize the credentials service.

        Args:
            db: SQLAlchemy database session.
        """
        self.db = db

    # ========================================================================
    # CRUD Operations
    # ========================================================================

    def get_credentials(self, store_id: int) -> StoreLetzshopCredentials | None:
        """
        Get Letzshop credentials for a store.

        Args:
            store_id: The store ID.

        Returns:
            StoreLetzshopCredentials or None if not found.
        """
        return (
            self.db.query(StoreLetzshopCredentials)
            .filter(StoreLetzshopCredentials.store_id == store_id)
            .first()
        )

    def get_credentials_or_raise(self, store_id: int) -> StoreLetzshopCredentials:
        """
        Get Letzshop credentials for a store or raise an exception.

        Args:
            store_id: The store ID.

        Returns:
            StoreLetzshopCredentials.

        Raises:
            CredentialsNotFoundError: If credentials are not found.
        """
        credentials = self.get_credentials(store_id)
        if credentials is None:
            raise CredentialsNotFoundError(
                f"Letzshop credentials not found for store {store_id}"
            )
        return credentials

    def create_credentials(
        self,
        store_id: int,
        api_key: str,
        api_endpoint: str | None = None,
        auto_sync_enabled: bool = False,
        sync_interval_minutes: int = 15,
    ) -> StoreLetzshopCredentials:
        """
        Create Letzshop credentials for a store.

        Args:
            store_id: The store ID.
            api_key: The Letzshop API key (will be encrypted).
            api_endpoint: Custom API endpoint (optional).
            auto_sync_enabled: Whether to enable automatic sync.
            sync_interval_minutes: Sync interval in minutes.

        Returns:
            Created StoreLetzshopCredentials.
        """
        # Encrypt the API key
        encrypted_key = encrypt_value(api_key)

        credentials = StoreLetzshopCredentials(
            store_id=store_id,
            api_key_encrypted=encrypted_key,
            api_endpoint=api_endpoint or DEFAULT_ENDPOINT,
            auto_sync_enabled=auto_sync_enabled,
            sync_interval_minutes=sync_interval_minutes,
        )

        self.db.add(credentials)
        self.db.flush()

        logger.info(f"Created Letzshop credentials for store {store_id}")
        return credentials

    def update_credentials(
        self,
        store_id: int,
        api_key: str | None = None,
        api_endpoint: str | None = None,
        auto_sync_enabled: bool | None = None,
        sync_interval_minutes: int | None = None,
    ) -> StoreLetzshopCredentials:
        """
        Update Letzshop credentials for a store.

        Args:
            store_id: The store ID.
            api_key: New API key (optional, will be encrypted if provided).
            api_endpoint: New API endpoint (optional).
            auto_sync_enabled: New auto-sync setting (optional).
            sync_interval_minutes: New sync interval (optional).

        Returns:
            Updated StoreLetzshopCredentials.

        Raises:
            CredentialsNotFoundError: If credentials are not found.
        """
        credentials = self.get_credentials_or_raise(store_id)

        if api_key is not None:
            credentials.api_key_encrypted = encrypt_value(api_key)
        if api_endpoint is not None:
            credentials.api_endpoint = api_endpoint
        if auto_sync_enabled is not None:
            credentials.auto_sync_enabled = auto_sync_enabled
        if sync_interval_minutes is not None:
            credentials.sync_interval_minutes = sync_interval_minutes

        self.db.flush()

        logger.info(f"Updated Letzshop credentials for store {store_id}")
        return credentials

    def delete_credentials(self, store_id: int) -> bool:
        """
        Delete Letzshop credentials for a store.

        Args:
            store_id: The store ID.

        Returns:
            True if deleted, False if not found.
        """
        credentials = self.get_credentials(store_id)
        if credentials is None:
            return False

        self.db.delete(credentials)
        self.db.flush()

        logger.info(f"Deleted Letzshop credentials for store {store_id}")
        return True

    def upsert_credentials(
        self,
        store_id: int,
        api_key: str,
        api_endpoint: str | None = None,
        auto_sync_enabled: bool = False,
        sync_interval_minutes: int = 15,
    ) -> StoreLetzshopCredentials:
        """
        Create or update Letzshop credentials for a store.

        Args:
            store_id: The store ID.
            api_key: The Letzshop API key (will be encrypted).
            api_endpoint: Custom API endpoint (optional).
            auto_sync_enabled: Whether to enable automatic sync.
            sync_interval_minutes: Sync interval in minutes.

        Returns:
            Created or updated StoreLetzshopCredentials.
        """
        existing = self.get_credentials(store_id)

        if existing:
            return self.update_credentials(
                store_id=store_id,
                api_key=api_key,
                api_endpoint=api_endpoint,
                auto_sync_enabled=auto_sync_enabled,
                sync_interval_minutes=sync_interval_minutes,
            )

        return self.create_credentials(
            store_id=store_id,
            api_key=api_key,
            api_endpoint=api_endpoint,
            auto_sync_enabled=auto_sync_enabled,
            sync_interval_minutes=sync_interval_minutes,
        )

    # ========================================================================
    # Key Decryption and Client Creation
    # ========================================================================

    def get_decrypted_api_key(self, store_id: int) -> str:
        """
        Get the decrypted API key for a store.

        Args:
            store_id: The store ID.

        Returns:
            Decrypted API key.

        Raises:
            CredentialsNotFoundError: If credentials are not found.
        """
        credentials = self.get_credentials_or_raise(store_id)
        return decrypt_value(credentials.api_key_encrypted)

    def get_masked_api_key(self, store_id: int) -> str:
        """
        Get a masked version of the API key for display.

        Args:
            store_id: The store ID.

        Returns:
            Masked API key (e.g., "sk-a***************").

        Raises:
            CredentialsNotFoundError: If credentials are not found.
        """
        api_key = self.get_decrypted_api_key(store_id)
        return mask_api_key(api_key)

    def create_client(self, store_id: int) -> LetzshopClient:
        """
        Create a Letzshop client for a store.

        Args:
            store_id: The store ID.

        Returns:
            Configured LetzshopClient.

        Raises:
            CredentialsNotFoundError: If credentials are not found.
        """
        credentials = self.get_credentials_or_raise(store_id)
        api_key = decrypt_value(credentials.api_key_encrypted)

        return LetzshopClient(
            api_key=api_key,
            endpoint=credentials.api_endpoint,
        )

    # ========================================================================
    # Connection Testing
    # ========================================================================

    def test_connection(self, store_id: int) -> tuple[bool, float | None, str | None]:
        """
        Test the connection for a store's credentials.

        Args:
            store_id: The store ID.

        Returns:
            Tuple of (success, response_time_ms, error_message).
        """
        try:
            with self.create_client(store_id) as client:
                return client.test_connection()
        except CredentialsNotFoundError:
            return False, None, "Letzshop credentials not configured"
        except Exception as e:
            logger.error(f"Connection test failed for store {store_id}: {e}")
            return False, None, str(e)

    def test_api_key(
        self,
        api_key: str,
        api_endpoint: str | None = None,
    ) -> tuple[bool, float | None, str | None]:
        """
        Test an API key without saving it.

        Args:
            api_key: The API key to test.
            api_endpoint: Optional custom endpoint.

        Returns:
            Tuple of (success, response_time_ms, error_message).
        """
        try:
            with LetzshopClient(
                api_key=api_key,
                endpoint=api_endpoint or DEFAULT_ENDPOINT,
            ) as client:
                return client.test_connection()
        except Exception as e:
            logger.error(f"API key test failed: {e}")
            return False, None, str(e)

    # ========================================================================
    # Sync Status Updates
    # ========================================================================

    def update_sync_status(
        self,
        store_id: int,
        status: str,
        error: str | None = None,
    ) -> StoreLetzshopCredentials | None:
        """
        Update the last sync status for a store.

        Args:
            store_id: The store ID.
            status: Sync status (success, failed, partial).
            error: Error message if sync failed.

        Returns:
            Updated credentials or None if not found.
        """
        credentials = self.get_credentials(store_id)
        if credentials is None:
            return None

        credentials.last_sync_at = datetime.now(UTC)
        credentials.last_sync_status = status
        credentials.last_sync_error = error

        self.db.flush()

        return credentials

    # ========================================================================
    # Status Helpers
    # ========================================================================

    def is_configured(self, store_id: int) -> bool:
        """Check if Letzshop is configured for a store."""
        return self.get_credentials(store_id) is not None

    def get_status(self, store_id: int) -> dict:
        """
        Get the Letzshop integration status for a store.

        Args:
            store_id: The store ID.

        Returns:
            Status dictionary with configuration and sync info.
        """
        credentials = self.get_credentials(store_id)

        if credentials is None:
            return {
                "is_configured": False,
                "is_connected": False,
                "last_sync_at": None,
                "last_sync_status": None,
                "auto_sync_enabled": False,
            }

        return {
            "is_configured": True,
            "is_connected": credentials.last_sync_status == "success",
            "last_sync_at": credentials.last_sync_at,
            "last_sync_status": credentials.last_sync_status,
            "auto_sync_enabled": credentials.auto_sync_enabled,
        }
