from __future__ import annotations
import json
import logging
from typing import Dict, List

from fastapi import Depends, HTTPException, status
from sqlalchemy.orm import Session

from src.core.database import get_db

logger = logging.getLogger(__name__)

CACHE_TTL = 300  # 5 minutes


def _get_redis():
    import redis as _redis
    from src.core.config import settings
    redis_url = (
        getattr(settings, "REDIS_URL", None)
        or getattr(settings, "CELERY_RESULT_BACKEND", "redis://localhost:6379/0")
    )
    r = _redis.from_url(redis_url, decode_responses=True)
    try:
        yield r
    finally:
        r.close()


def _cache_key(merchant_id: int) -> str:
    return f"feature:{merchant_id}"


class FeatureService:
    @staticmethod
    def resolve(db: Session, redis_client, merchant_id: int) -> Dict[str, bool]:
        key = _cache_key(merchant_id)
        try:
            cached = redis_client.get(key)
            if cached:
                return json.loads(cached)
        except Exception:
            pass

        import src.apps.feature_control.crud as crud

        flags = {f.slug: f.is_default for f in crud.get_all_active_flags(db)}

        assignment = crud.get_active_plan_assignment(db, merchant_id)
        if assignment:
            for item in assignment.plan.items:
                flags[item.feature_slug] = item.is_enabled

        for override in crud.get_overrides(db, merchant_id):
            flags[override.feature_slug] = override.is_enabled

        try:
            redis_client.setex(key, CACHE_TTL, json.dumps(flags))
        except Exception:
            pass

        return flags

    @staticmethod
    def invalidate(redis_client, merchant_id: int) -> None:
        try:
            redis_client.delete(_cache_key(merchant_id))
        except Exception:
            pass

    @staticmethod
    def invalidate_bulk(redis_client, merchant_ids: List[int]) -> None:
        if not merchant_ids:
            return
        keys = [_cache_key(mid) for mid in merchant_ids]
        try:
            redis_client.delete(*keys)
        except Exception:
            pass


def require_feature(slug: str):
    from src.apps.merchants.models.merchant import Merchant
    from src.apps.auth.utils.auth import get_current_merchant

    async def _check(
        merchant: Merchant = Depends(get_current_merchant),
        db: Session = Depends(get_db),
        redis_client=Depends(_get_redis),
    ):
        features = FeatureService.resolve(db, redis_client, merchant.id)
        if not features.get(slug, False):
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail={"error": "feature_not_enabled", "feature": slug},
            )

    return Depends(_check)
