from __future__ import annotations

from datetime import datetime, timedelta
import logging
from typing import Any, Dict, Optional

import httpx
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from .. import settings
from ..models import Integration, IntegrationProvider, IntegrationStatus
from .secret_storage import get_saas_secret_backend

logger = logging.getLogger(__name__)

APOLLO_TOKEN_URL = "https://app.apollo.io/api/v1/oauth/token"
APOLLO_TOKEN_TTL_SECONDS = 60 * 60 * 24 * 30  # 30 days default


def _compute_expires_at(tokens: Dict[str, Any]) -> datetime:
    ttl = tokens.get("expires_in")
    try:
        ttl_value = int(ttl)
    except (TypeError, ValueError):
        ttl_value = APOLLO_TOKEN_TTL_SECONDS
    return datetime.utcnow() + timedelta(seconds=ttl_value)


async def get_apollo_integration(
    db: AsyncSession,
    account_id: str,
) -> Optional[Integration]:
    result = await db.execute(
        select(Integration).where(
            Integration.account_id == str(account_id),
            Integration.provider == IntegrationProvider.APOLLO,
        )
    )
    return result.scalar_one_or_none()


async def get_or_create_apollo_integration(
    db: AsyncSession,
    account_id: str,
) -> Integration:
    integration = await get_apollo_integration(db, account_id)
    if integration:
        return integration

    integration = Integration(
        account_id=str(account_id),
        provider=IntegrationProvider.APOLLO,
        status=IntegrationStatus.DISCONNECTED,
    )
    db.add(integration)
    await db.flush()
    return integration


async def store_apollo_tokens(
    db: AsyncSession,
    account_id: str,
    tokens: Dict[str, Any],
    created_by: Optional[str] = None,
) -> Integration:
    secret_backend = get_saas_secret_backend()
    await secret_backend.set_secret(
        db=db,
        integration="apollo",
        key="access_token",
        value=tokens["access_token"],
        workspace_id=str(account_id),
        created_by=created_by,
    )
    await secret_backend.set_secret(
        db=db,
        integration="apollo",
        key="refresh_token",
        value=tokens["refresh_token"],
        workspace_id=str(account_id),
        created_by=created_by,
    )

    integration = await get_or_create_apollo_integration(db, account_id)
    integration.status = IntegrationStatus.CONNECTED
    config = dict(integration.config or {})
    config["expires_at"] = _compute_expires_at(tokens).isoformat()
    config.setdefault("connected_at", datetime.utcnow().isoformat())
    integration.config = config
    integration.updated_at = datetime.utcnow()
    return integration


async def refresh_apollo_tokens(db: AsyncSession, account_id: str) -> bool:
    """Refresh Apollo tokens. Server-side only."""
    if not settings.APOLLO_CLIENT_ID or not settings.APOLLO_CLIENT_SECRET:
        logger.warning("Apollo OAuth not configured; cannot refresh tokens.")
        return False

    stmt = (
        select(Integration)
        .where(
            Integration.account_id == str(account_id),
            Integration.provider == IntegrationProvider.APOLLO,
        )
        .with_for_update()
    )
    result = await db.execute(stmt)
    integration = result.scalar_one_or_none()
    if not integration or integration.status != IntegrationStatus.CONNECTED:
        return False

    secret_backend = get_saas_secret_backend()
    refresh_secret = await secret_backend.get_secret(
        db=db,
        integration="apollo",
        key="refresh_token",
        workspace_id=str(account_id),
    )
    if not refresh_secret:
        integration.status = IntegrationStatus.ERROR
        integration.updated_at = datetime.utcnow()
        await db.commit()
        return False

    async with httpx.AsyncClient(timeout=30.0) as client:
        response = await client.post(
            APOLLO_TOKEN_URL,
            data={
                "grant_type": "refresh_token",
                "refresh_token": refresh_secret.value,
                "client_id": settings.APOLLO_CLIENT_ID,
                "client_secret": settings.APOLLO_CLIENT_SECRET,
            },
        )

    if not response.is_success:
        integration.status = IntegrationStatus.ERROR
        integration.updated_at = datetime.utcnow()
        await db.commit()
        logger.warning(
            "Apollo token refresh failed for %s: %s",
            account_id,
            response.text,
        )
        return False

    tokens = response.json()
    if not tokens.get("access_token") or not tokens.get("refresh_token"):
        integration.status = IntegrationStatus.ERROR
        integration.updated_at = datetime.utcnow()
        await db.commit()
        logger.warning(
            "Apollo token refresh response missing tokens for %s: %s",
            account_id,
            tokens,
        )
        return False
    await secret_backend.set_secret(
        db=db,
        integration="apollo",
        key="access_token",
        value=tokens["access_token"],
        workspace_id=str(account_id),
        created_by="system",
    )
    await secret_backend.set_secret(
        db=db,
        integration="apollo",
        key="refresh_token",
        value=tokens["refresh_token"],
        workspace_id=str(account_id),
        created_by="system",
    )

    config = dict(integration.config or {})
    config["expires_at"] = _compute_expires_at(tokens).isoformat()
    config["refreshed_at"] = datetime.utcnow().isoformat()
    integration.status = IntegrationStatus.CONNECTED
    integration.config = config
    integration.updated_at = datetime.utcnow()
    await db.commit()
    return True
