import logging
from dataclasses import dataclass
from typing import List, Optional

from sqlalchemy.ext.asyncio import AsyncSession

from app.config import settings
from app.database.crud.campaign import record_campaign_registration
from app.database.crud.subscription import (
    create_paid_subscription,
    get_subscription_by_user_id,
)
from app.database.crud.user import add_user_balance
from app.database.models import AdvertisingCampaign, User
from app.services.subscription_service import SubscriptionService

logger = logging.getLogger(__name__)


@dataclass
class CampaignBonusResult:
    success: bool
    bonus_type: Optional[str] = None
    balance_kopeks: int = 0
    subscription_days: Optional[int] = None
    subscription_traffic_gb: Optional[int] = None
    subscription_device_limit: Optional[int] = None
    subscription_squads: Optional[List[str]] = None


class AdvertisingCampaignService:
    def __init__(self) -> None:
        self.subscription_service = SubscriptionService()

    async def apply_campaign_bonus(
        self,
        db: AsyncSession,
        user: User,
        campaign: AdvertisingCampaign,
    ) -> CampaignBonusResult:
        if not campaign.is_active:
            logger.warning(
                "⚠️ Попытка выдать бонус по неактивной кампании %s", campaign.id
            )
            return CampaignBonusResult(success=False)

        if campaign.is_balance_bonus:
            return await self._apply_balance_bonus(db, user, campaign)

        if campaign.is_subscription_bonus:
            return await self._apply_subscription_bonus(db, user, campaign)

        logger.error("❌ Неизвестный тип бонуса кампании: %s", campaign.bonus_type)
        return CampaignBonusResult(success=False)

    async def _apply_balance_bonus(
        self,
        db: AsyncSession,
        user: User,
        campaign: AdvertisingCampaign,
    ) -> CampaignBonusResult:
        amount = campaign.balance_bonus_kopeks or 0
        if amount <= 0:
            logger.info("ℹ️ Кампания %s не имеет бонуса на баланс", campaign.id)
            return CampaignBonusResult(success=False)

        description = f"Бонус за регистрацию по кампании '{campaign.name}'"
        success = await add_user_balance(
            db,
            user,
            amount,
            description=description,
        )

        if not success:
            return CampaignBonusResult(success=False)

        await record_campaign_registration(
            db,
            campaign_id=campaign.id,
            user_id=user.id,
            bonus_type="balance",
            balance_bonus_kopeks=amount,
        )

        logger.info(
            "💰 Пользователю %s начислен бонус %s₽ по кампании %s",
            user.telegram_id,
            amount / 100,
            campaign.id,
        )

        return CampaignBonusResult(
            success=True,
            bonus_type="balance",
            balance_kopeks=amount,
        )

    async def _apply_subscription_bonus(
        self,
        db: AsyncSession,
        user: User,
        campaign: AdvertisingCampaign,
    ) -> CampaignBonusResult:
        existing_subscription = await get_subscription_by_user_id(db, user.id)
        if existing_subscription:
            logger.warning(
                "⚠️ У пользователя %s уже есть подписка, бонус кампании %s пропущен",
                user.telegram_id,
                campaign.id,
            )
            return CampaignBonusResult(success=False)

        duration_days = campaign.subscription_duration_days or 0
        if duration_days <= 0:
            logger.info(
                "ℹ️ Кампания %s не содержит корректной длительности подписки",
                campaign.id,
            )
            return CampaignBonusResult(success=False)

        traffic_limit = campaign.subscription_traffic_gb
        device_limit = (
            campaign.subscription_device_limit or settings.DEFAULT_DEVICE_LIMIT
        )
        squads = list(campaign.subscription_squads or [])

        if not squads and getattr(settings, "TRIAL_SQUAD_UUID", None):
            squads = [settings.TRIAL_SQUAD_UUID]

        new_subscription = await create_paid_subscription(
            db=db,
            user_id=user.id,
            duration_days=duration_days,
            traffic_limit_gb=traffic_limit or 0,
            device_limit=device_limit,
            connected_squads=squads,
        )

        try:
            await self.subscription_service.create_remnawave_user(db, new_subscription)
        except Exception as error:
            logger.error(
                "❌ Ошибка синхронизации RemnaWave для кампании %s: %s",
                campaign.id,
                error,
            )

        await record_campaign_registration(
            db,
            campaign_id=campaign.id,
            user_id=user.id,
            bonus_type="subscription",
            subscription_duration_days=duration_days,
        )

        logger.info(
            "🎁 Пользователю %s выдана подписка по кампании %s на %s дней",
            user.telegram_id,
            campaign.id,
            duration_days,
        )

        return CampaignBonusResult(
            success=True,
            bonus_type="subscription",
            subscription_days=duration_days,
            subscription_traffic_gb=traffic_limit or 0,
            subscription_device_limit=device_limit,
            subscription_squads=squads,
        )
