"""Пример: Система автоматического управления подписками.

Этот пример показывает, как создать полноценную систему управления
VPN подписками с автоматическим продлением и уведомлениями.
"""

import asyncio
from datetime import date, timedelta
from typing import Optional
from amnezio import AmnezioClient
from amnezio.exceptions import NotFoundError, APIError


class SubscriptionManager:
    """Менеджер подписок с автоматическим управлением."""
    
    def __init__(
        self,
        panel_url: str,
        username: str,
        password: str,
        default_profile_id: int = 1
    ):
        self.panel_url = panel_url
        self.username = username
        self.password = password
        self.default_profile_id = default_profile_id
    
    async def create_subscription(
        self,
        user_id: str,
        telegram_id: Optional[int] = None,
        email: Optional[str] = None,
        days: int = 30
    ) -> dict:
        """
        Создать новую подписку.
        
        Args:
            user_id: Уникальный ID пользователя
            telegram_id: ID в Telegram (опционально)
            email: Email для уведомлений (опционально)
            days: Количество дней подписки
        
        Returns:
            dict: Данные созданной подписки
        """
        async with AmnezioClient(
            base_url=self.panel_url,
            username=self.username,
            password=self.password
        ) as client:
            # Генерация ключей
            keypair = await client.users.generate_keypair()
            
            # Создание пользователя
            description = []
            if telegram_id:
                description.append(f"Telegram ID: {telegram_id}")
            if email:
                description.append(f"Email: {email}")
            
            user = await client.users.create(
                sub_id=user_id,
                private_key=keypair.private_key,
                preshared_key=keypair.preshared_key,
                telegram_id=telegram_id,
                profile_id=self.default_profile_id,
                paid_for=date.today() + timedelta(days=days),
                tag="subscription",
                description=", ".join(description) if description else None
            )
            
            # Получение конфига
            config = await client.users.get_config(user.id)
            qrcode = await client.users.get_qrcode(user.id)
            
            return {
                "user_id": user.id,
                "sub_id": user.sub_id,
                "assigned_ip": user.assigned_ip,
                "paid_for": user.paid_for,
                "config": config.config,
                "qrcode": qrcode,
                "private_key": keypair.private_key,
                "public_key": keypair.public_key,
            }
    
    async def check_expiring_subscriptions(self, days_before: int = 3) -> list[dict]:
        """
        Проверить подписки, истекающие в ближайшие дни.
        
        Args:
            days_before: За сколько дней до истечения проверять
        
        Returns:
            list: Список пользователей с истекающими подписками
        """
        async with AmnezioClient(
            base_url=self.panel_url,
            username=self.username,
            password=self.password
        ) as client:
            expiring = []
            threshold = date.today() + timedelta(days=days_before)
            
            # Проходим по всем пользователям
            page = 1
            per_page = 100
            
            while True:
                result = await client.users.list(page=page, per_page=per_page)
                
                for user in result.items:
                    # Пропускаем отключенных
                    if user.status != "active":
                        continue
                    
                    # Проверяем дату истечения
                    if user.paid_for and user.paid_for <= threshold:
                        days_left = (user.paid_for - date.today()).days
                        
                        expiring.append({
                            "user_id": user.id,
                            "sub_id": user.sub_id,
                            "telegram_id": user.telegram_id,
                            "paid_for": user.paid_for,
                            "days_left": days_left,
                            "is_expired": days_left < 0,
                        })
                
                if page >= result.total_pages:
                    break
                page += 1
            
            return expiring
    
    async def auto_disable_expired(self) -> list[dict]:
        """
        Автоматически отключить истекшие подписки.
        
        Returns:
            list: Список отключенных пользователей
        """
        async with AmnezioClient(
            base_url=self.panel_url,
            username=self.username,
            password=self.password
        ) as client:
            disabled = []
            today = date.today()
            
            # Проходим по всем пользователям
            page = 1
            per_page = 100
            
            while True:
                result = await client.users.list(page=page, per_page=per_page)
                
                for user in result.items:
                    # Пропускаем уже отключенных
                    if user.status != "active":
                        continue
                    
                    # Проверяем истечение
                    if user.paid_for and user.paid_for < today:
                        await client.users.disable(user.id)
                        
                        disabled.append({
                            "user_id": user.id,
                            "sub_id": user.sub_id,
                            "telegram_id": user.telegram_id,
                            "expired_on": user.paid_for,
                        })
                
                if page >= result.total_pages:
                    break
                page += 1
            
            return disabled
    
    async def renew_subscription(
        self,
        user_id: int,
        days: int = 30,
        enable: bool = True
    ) -> dict:
        """
        Продлить подписку.
        
        Args:
            user_id: ID пользователя
            days: На сколько дней продлить
            enable: Включить ли пользователя при продлении
        
        Returns:
            dict: Обновленные данные
        """
        async with AmnezioClient(
            base_url=self.panel_url,
            username=self.username,
            password=self.password
        ) as client:
            # Получаем пользователя
            user = await client.users.get(user_id)
            
            # Вычисляем новую дату
            if user.paid_for and user.paid_for >= date.today():
                new_date = user.paid_for + timedelta(days=days)
            else:
                new_date = date.today() + timedelta(days=days)
            
            # Продлеваем
            if enable:
                user = await client.users.renew_subscription(user_id, new_date)
            else:
                user = await client.users.update(user_id, paid_for=new_date)
            
            return {
                "user_id": user.id,
                "sub_id": user.sub_id,
                "paid_for": user.paid_for,
                "status": user.status,
                "days_left": (user.paid_for - date.today()).days,
            }
    
    async def get_statistics(self) -> dict:
        """
        Получить общую статистику по подпискам.
        
        Returns:
            dict: Статистика
        """
        async with AmnezioClient(
            base_url=self.panel_url,
            username=self.username,
            password=self.password
        ) as client:
            total_users = 0
            active_users = 0
            disabled_users = 0
            expired_users = 0
            expiring_soon = 0  # В течение 3 дней
            
            total_rx = 0
            total_tx = 0
            
            today = date.today()
            threshold = today + timedelta(days=3)
            
            page = 1
            per_page = 100
            
            while True:
                result = await client.users.list(page=page, per_page=per_page)
                
                for user in result.items:
                    total_users += 1
                    total_rx += user.rx_bytes
                    total_tx += user.tx_bytes
                    
                    if user.status == "active":
                        active_users += 1
                        
                        # Проверка истечения
                        if user.paid_for:
                            if user.paid_for < today:
                                expired_users += 1
                            elif user.paid_for <= threshold:
                                expiring_soon += 1
                    else:
                        disabled_users += 1
                
                if page >= result.total_pages:
                    break
                page += 1
            
            return {
                "total_users": total_users,
                "active_users": active_users,
                "disabled_users": disabled_users,
                "expired_users": expired_users,
                "expiring_soon": expiring_soon,
                "total_traffic_gb": (total_rx + total_tx) / (1024**3),
            }


# Пример использования с периодической проверкой
async def subscription_monitoring_task():
    """
    Фоновая задача для мониторинга подписок.
    Запускается раз в день.
    """
    manager = SubscriptionManager(
        panel_url="https://panel.example.com",
        username="admin",
        password="secret"
    )
    
    while True:
        try:
            print("=== Проверка подписок ===")
            
            # 1. Отключение истекших
            disabled = await manager.auto_disable_expired()
            print(f"Отключено истекших подписок: {len(disabled)}")
            
            # 2. Проверка истекающих в ближайшие 3 дня
            expiring = await manager.check_expiring_subscriptions(days_before=3)
            print(f"Истекает в ближайшие 3 дня: {len(expiring)}")
            
            # Здесь можно отправить уведомления
            for user in expiring:
                if user["telegram_id"]:
                    print(f"  Уведомить Telegram {user['telegram_id']}: осталось {user['days_left']} дней")
            
            # 3. Статистика
            stats = await manager.get_statistics()
            print(f"\nСтатистика:")
            print(f"  Всего пользователей: {stats['total_users']}")
            print(f"  Активных: {stats['active_users']}")
            print(f"  Отключенных: {stats['disabled_users']}")
            print(f"  Истекших: {stats['expired_users']}")
            print(f"  Истекает скоро: {stats['expiring_soon']}")
            print(f"  Общий трафик: {stats['total_traffic_gb']:.2f} GB")
            
        except Exception as e:
            print(f"Ошибка при проверке подписок: {e}")
        
        # Ждем 24 часа до следующей проверки
        await asyncio.sleep(24 * 60 * 60)


# Пример интеграции с FastAPI
"""
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI()
manager = SubscriptionManager(...)

class CreateSubscriptionRequest(BaseModel):
    user_id: str
    telegram_id: int | None = None
    email: str | None = None
    days: int = 30

@app.post("/api/subscriptions")
async def create_subscription(request: CreateSubscriptionRequest):
    try:
        result = await manager.create_subscription(
            user_id=request.user_id,
            telegram_id=request.telegram_id,
            email=request.email,
            days=request.days
        )
        return result
    except APIError as e:
        raise HTTPException(status_code=e.status_code, detail=e.message)

@app.get("/api/subscriptions/expiring")
async def get_expiring_subscriptions(days_before: int = 3):
    return await manager.check_expiring_subscriptions(days_before)

@app.get("/api/statistics")
async def get_statistics():
    return await manager.get_statistics()

@app.post("/api/subscriptions/{user_id}/renew")
async def renew_subscription(user_id: int, days: int = 30):
    try:
        return await manager.renew_subscription(user_id, days)
    except NotFoundError:
        raise HTTPException(status_code=404, detail="User not found")
"""


if __name__ == "__main__":
    # Запуск фоновой задачи
    asyncio.run(subscription_monitoring_task())
