import json
from typing import Callable, Awaitable
from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware
from ...content.schemas.privacy import CookieConsent, CookieCategoryPreferences
from ...shared.config.settings import settings
from ...shared.config.logging_config import get_logger
logger = get_logger(__name__)
COOKIE_CONSENT_COOKIE_NAME = 'cookieConsent'

def _parse_consent_cookie(raw_value: str | None) -> CookieConsent:
    if not raw_value:
        return CookieConsent()
    try:
        data = json.loads(raw_value)
        return CookieConsent(**data)
    except Exception as exc:
        logger.warning(f'Failed to parse cookie consent cookie: {exc}')
        return CookieConsent()

class CookieConsentMiddleware(BaseHTTPMiddleware):

    async def dispatch(self, request: Request, call_next: Callable[[Request], Awaitable[Response]]) -> Response:
        raw_cookie = request.cookies.get(COOKIE_CONSENT_COOKIE_NAME)
        consent = _parse_consent_cookie(raw_cookie)
        consent.categories.necessary = True
        request.state.cookie_consent = consent
        response = await call_next(request)
        if COOKIE_CONSENT_COOKIE_NAME not in request.cookies:
            try:
                response.set_cookie(key=COOKIE_CONSENT_COOKIE_NAME, value=consent.model_dump_json(), httponly=True, secure=settings.is_production, samesite='lax', max_age=365 * 24 * 60 * 60, path='/')
            except Exception as exc:
                logger.warning(f'Failed to set default cookie consent cookie: {exc}')
        return response

def is_analytics_allowed(request: Request) -> bool:
    consent: CookieConsent | None = getattr(request.state, 'cookie_consent', None)
    if not consent:
        return False
    return consent.categories.analytics

def is_marketing_allowed(request: Request) -> bool:
    consent: CookieConsent | None = getattr(request.state, 'cookie_consent', None)
    if not consent:
        return False
    return consent.categories.marketing

def is_preferences_allowed(request: Request) -> bool:
    consent: CookieConsent | None = getattr(request.state, 'cookie_consent', None)
    if not consent:
        return False
    return consent.categories.preferences