"""
API для управления биллингом и тарифами
"""
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from sqlalchemy import func, and_
from typing import List, Optional
from datetime import datetime, timedelta
from decimal import Decimal

from app.db.session import get_db
from app.db.models import (
    Plan, Subscription, UsageRecord, Payment, LimitAlert, 
    Tenant, Notification, Delivery
)
from app.api.deps import get_current_user
from pydantic import BaseModel, Field

router = APIRouter()


# Pydantic схемы
class PlanOut(BaseModel):
    id: int
    name: str
    description: Optional[str]
    monthly_price: Decimal
    notifications_limit: int
    features: dict
    is_active: bool

    class Config:
        from_attributes = True


class SubscriptionOut(BaseModel):
    id: int
    tenant_id: int
    plan_id: int
    plan: PlanOut
    status: str
    started_at: datetime
    expires_at: Optional[datetime]
    auto_renew: bool

    class Config:
        from_attributes = True


class UsageOut(BaseModel):
    notifications_sent: int
    notifications_limit: int
    percentage_used: float
    period_start: datetime
    period_end: datetime


class PaymentOut(BaseModel):
    id: int
    amount: Decimal
    currency: str
    status: str
    payment_method: Optional[str]
    transaction_id: Optional[str]
    created_at: datetime
    completed_at: Optional[datetime]

    class Config:
        from_attributes = True


class LimitAlertOut(BaseModel):
    id: int
    alert_type: str
    threshold: int
    current_usage: int
    limit_value: int
    message: Optional[str]
    created_at: datetime

    class Config:
        from_attributes = True


class SubscriptionCreate(BaseModel):
    plan_id: int
    auto_renew: bool = True


class PaymentCreate(BaseModel):
    subscription_id: int
    amount: Decimal
    payment_method: str
    transaction_id: Optional[str] = None


# Эндпоинты

@router.get("/plans", response_model=List[PlanOut])
def get_plans(db: Session = Depends(get_db)):
    """Получить список всех доступных тарифных планов (публичный эндпоинт)"""
    plans = db.query(Plan).filter(Plan.is_active == True).all()
    return plans


@router.get("/subscription", response_model=SubscriptionOut)
def get_current_subscription(
    db: Session = Depends(get_db),
    current_user = Depends(get_current_user)
):
    """Получить текущую подписку тенанта"""
    subscription = db.query(Subscription).filter(
        and_(
            Subscription.tenant_id == current_user.tenant_id,
            Subscription.status.in_(["active", "pending_payment"])
        )
    ).order_by(Subscription.created_at.desc()).first()
    
    if not subscription:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Подписка не найдена"
        )
    
    return subscription


@router.post("/subscription", response_model=SubscriptionOut, status_code=201)
def create_subscription(
    data: SubscriptionCreate,
    db: Session = Depends(get_db),
    current_user = Depends(get_current_user)
):
    """Создать новую подписку (обновить тариф)"""
    # Проверяем существование плана
    plan = db.query(Plan).filter(Plan.id == data.plan_id).first()
    if not plan:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="План не найден"
        )
    
    # Проверяем текущую активную подписку
    current_subscription = db.query(Subscription).filter(
        and_(
            Subscription.tenant_id == current_user.tenant_id,
            Subscription.status == "active"
        )
    ).first()
    
    # Проверяем подписку в статусе pending_payment
    pending_subscription = db.query(Subscription).filter(
        and_(
            Subscription.tenant_id == current_user.tenant_id,
            Subscription.status == "pending_payment"
        )
    ).first()
    
    # Если переключаемся на тот же тариф и подписка активна - просто обновляем auto_renew и возвращаем
    if current_subscription and current_subscription.plan_id == data.plan_id:
        current_subscription.auto_renew = data.auto_renew
        db.commit()
        db.refresh(current_subscription)
        return current_subscription
    
    # Если есть подписка в статусе pending_payment на тот же тариф - просто обновляем auto_renew
    if pending_subscription and pending_subscription.plan_id == data.plan_id:
        pending_subscription.auto_renew = data.auto_renew
        db.commit()
        db.refresh(pending_subscription)
        return pending_subscription
    
    # Отменяем все подписки в статусе pending_payment при создании новой
    if pending_subscription:
        pending_subscription.status = "cancelled"
    
    # Для платных тарифов проверяем баланс и списываем средства сразу
    if plan.monthly_price > 0:
        from app.db.models import UserBalance, BalanceTransaction
        
        # Получаем баланс пользователя с блокировкой для предотвращения race condition
        balance = db.query(UserBalance).filter(
            UserBalance.tenant_id == current_user.tenant_id
        ).with_for_update().first()
        
        if not balance:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Баланс не найден. Пополните баланс для выбора платного тарифа."
            )
        
        amount = Decimal(str(plan.monthly_price))
        
        # Проверяем достаточность средств
        if balance.balance < amount:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Недостаточно средств на балансе. Требуется {amount} Р, доступно {balance.balance} Р. Пополните баланс для выбора этого тарифа."
            )
        
        # Списываем средства сразу
        balance_before = balance.balance
        balance.balance -= amount
        balance.total_spent += amount
        
        # Создаем транзакцию списания
        transaction = BalanceTransaction(
            tenant_id=current_user.tenant_id,
            transaction_type="subscription_payment",
            amount=-amount,  # Отрицательная сумма для списания
            balance_before=balance_before,
            balance_after=balance.balance,
            description=f"Оплата подписки {plan.name}",
            reference_id=None  # Будет установлен после создания подписки
        )
        db.add(transaction)
        
        # Платный тариф активируется сразу после списания средств
        subscription_status = "active"
    else:
        # Бесплатный тариф активируется сразу
        subscription_status = "active"
    
    # Создаем новую подписку
    subscription = Subscription(
        tenant_id=current_user.tenant_id,
        plan_id=data.plan_id,
        status=subscription_status,
        started_at=datetime.utcnow(),
        expires_at=datetime.utcnow() + timedelta(days=30),
        auto_renew=data.auto_renew
    )
    db.add(subscription)
    db.flush()  # Получаем ID подписки
    
    # Обновляем reference_id в транзакции, если она была создана
    if plan.monthly_price > 0:
        transaction.reference_id = str(subscription.id)
    
    # Отменяем старую активную подписку
    if current_subscription:
        current_subscription.status = "cancelled"
    
    # Создаем запись об использовании
    usage = UsageRecord(
        tenant_id=current_user.tenant_id,
        subscription_id=subscription.id,
        period_start=datetime.utcnow(),
        period_end=datetime.utcnow() + timedelta(days=30),
        notifications_sent=0,
        notifications_limit=plan.notifications_limit
    )
    db.add(usage)
    
    # Создаем запись о платеже для платных тарифов
    if plan.monthly_price > 0:
        payment = Payment(
            tenant_id=current_user.tenant_id,
            subscription_id=subscription.id,
            amount=amount,
            currency="RUB",
            status="completed",
            payment_method="balance",
            transaction_id=f"BALANCE-{int(datetime.utcnow().timestamp())}",
            completed_at=datetime.utcnow()
        )
        db.add(payment)
    
    db.commit()
    db.refresh(subscription)
    
    return subscription


@router.get("/usage", response_model=UsageOut)
def get_usage(
    db: Session = Depends(get_db),
    current_user = Depends(get_current_user)
):
    """Получить текущее использование лимитов"""
    # Получаем активную подписку
    subscription = db.query(Subscription).filter(
        and_(
            Subscription.tenant_id == current_user.tenant_id,
            Subscription.status == "active"
        )
    ).first()
    
    if not subscription:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Активная подписка не найдена"
        )
    
    # Получаем текущую запись об использовании
    now = datetime.utcnow()
    usage = db.query(UsageRecord).filter(
        and_(
            UsageRecord.subscription_id == subscription.id,
            UsageRecord.period_start <= now,
            UsageRecord.period_end >= now
        )
    ).first()
    
    if not usage:
        # Создаем новую запись, если не найдена
        usage = UsageRecord(
            tenant_id=current_user.tenant_id,
            subscription_id=subscription.id,
            period_start=now,
            period_end=now + timedelta(days=30),
            notifications_sent=0,
            notifications_limit=subscription.plan.notifications_limit
        )
        db.add(usage)
        db.commit()
        db.refresh(usage)
    
    # Подсчитываем реальное количество отправленных уведомлений
    sent_count = db.query(func.count(Notification.id)).filter(
        and_(
            Notification.tenant_id == current_user.tenant_id,
            Notification.created_at >= usage.period_start,
            Notification.created_at <= usage.period_end
        )
    ).scalar()
    
    # Обновляем запись
    usage.notifications_sent = sent_count
    db.commit()
    
    percentage_used = (sent_count / usage.notifications_limit * 100) if usage.notifications_limit > 0 else 0
    
    return UsageOut(
        notifications_sent=sent_count,
        notifications_limit=usage.notifications_limit,
        percentage_used=round(percentage_used, 2),
        period_start=usage.period_start,
        period_end=usage.period_end
    )


@router.get("/payments", response_model=List[PaymentOut])
def get_payments(
    limit: int = 50,
    offset: int = 0,
    db: Session = Depends(get_db),
    current_user = Depends(get_current_user)
):
    """Получить историю платежей"""
    payments = db.query(Payment).filter(
        Payment.tenant_id == current_user.tenant_id
    ).order_by(Payment.created_at.desc()).offset(offset).limit(limit).all()
    
    return payments


@router.post("/payments", response_model=PaymentOut, status_code=201)
def create_payment(
    data: PaymentCreate,
    db: Session = Depends(get_db),
    current_user = Depends(get_current_user)
):
    """Создать новый платеж"""
    # Проверяем подписку
    subscription = db.query(Subscription).filter(
        and_(
            Subscription.id == data.subscription_id,
            Subscription.tenant_id == current_user.tenant_id
        )
    ).first()
    
    if not subscription:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Подписка не найдена"
        )
    
    payment = Payment(
        tenant_id=current_user.tenant_id,
        subscription_id=data.subscription_id,
        amount=data.amount,
        status="completed",  # В реальности здесь будет интеграция с платежной системой
        payment_method=data.payment_method,
        transaction_id=data.transaction_id or f"TXN-{datetime.utcnow().timestamp()}",
        completed_at=datetime.utcnow()
    )
    db.add(payment)
    db.commit()
    db.refresh(payment)
    
    return payment


@router.get("/alerts", response_model=List[LimitAlertOut])
def get_limit_alerts(
    limit: int = 20,
    db: Session = Depends(get_db),
    current_user = Depends(get_current_user)
):
    """Получить уведомления о превышении лимитов"""
    alerts = db.query(LimitAlert).filter(
        LimitAlert.tenant_id == current_user.tenant_id
    ).order_by(LimitAlert.created_at.desc()).limit(limit).all()
    
    return alerts


@router.post("/check-limits")
def check_limits(
    db: Session = Depends(get_db),
    current_user = Depends(get_current_user)
):
    """Проверить лимиты и создать алерты при необходимости"""
    # Получаем текущее использование
    subscription = db.query(Subscription).filter(
        and_(
            Subscription.tenant_id == current_user.tenant_id,
            Subscription.status == "active"
        )
    ).first()
    
    if not subscription:
        return {"message": "Нет активной подписки"}
    
    now = datetime.utcnow()
    usage = db.query(UsageRecord).filter(
        and_(
            UsageRecord.subscription_id == subscription.id,
            UsageRecord.period_start <= now,
            UsageRecord.period_end >= now
        )
    ).first()
    
    if not usage:
        return {"message": "Нет записей об использовании"}
    
    # Подсчитываем процент использования
    sent_count = db.query(func.count(Notification.id)).filter(
        and_(
            Notification.tenant_id == current_user.tenant_id,
            Notification.created_at >= usage.period_start,
            Notification.created_at <= usage.period_end
        )
    ).scalar()
    
    percentage = (sent_count / usage.notifications_limit * 100) if usage.notifications_limit > 0 else 0
    
    # Создаем алерты
    alerts_created = []
    
    if percentage >= 100:
        alert = LimitAlert(
            tenant_id=current_user.tenant_id,
            alert_type="exceeded",
            threshold=100,
            current_usage=sent_count,
            limit_value=usage.notifications_limit,
            message=f"Лимит превышен! Использовано {sent_count} из {usage.notifications_limit} уведомлений."
        )
        db.add(alert)
        alerts_created.append("exceeded")
    elif percentage >= 90:
        alert = LimitAlert(
            tenant_id=current_user.tenant_id,
            alert_type="critical",
            threshold=90,
            current_usage=sent_count,
            limit_value=usage.notifications_limit,
            message=f"Критический уровень! Использовано {sent_count} из {usage.notifications_limit} уведомлений ({percentage:.1f}%)."
        )
        db.add(alert)
        alerts_created.append("critical")
    elif percentage >= 80:
        alert = LimitAlert(
            tenant_id=current_user.tenant_id,
            alert_type="warning",
            threshold=80,
            current_usage=sent_count,
            limit_value=usage.notifications_limit,
            message=f"Предупреждение! Использовано {sent_count} из {usage.notifications_limit} уведомлений ({percentage:.1f}%)."
        )
        db.add(alert)
        alerts_created.append("warning")
    
    if alerts_created:
        db.commit()
    
    return {
        "percentage_used": round(percentage, 2),
        "alerts_created": alerts_created,
        "current_usage": sent_count,
        "limit": usage.notifications_limit
    }


@router.post("/subscription/activate")
def activate_subscription(
    data: dict,
    db: Session = Depends(get_db),
    current_user = Depends(get_current_user)
):
    """Активировать подписку после успешной оплаты"""
    from app.db.models import UserBalance, BalanceTransaction
    from decimal import Decimal
    
    subscription_id = data.get("subscription_id")
    payment_method = data.get("payment_method", "demo")
    amount = Decimal(str(data.get("amount", 0)))
    
    if not subscription_id:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="ID подписки не указан"
        )
    
    # Находим подписку
    subscription = db.query(Subscription).filter(
        and_(
            Subscription.id == subscription_id,
            Subscription.tenant_id == current_user.tenant_id,
            Subscription.status == "pending_payment"
        )
    ).first()
    
    if not subscription:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Подписка не найдена или уже активирована"
        )
    
    # Если оплата с баланса, проверяем и списываем средства
    if payment_method == "balance":
        # Получаем баланс пользователя
        balance = db.query(UserBalance).filter(
            UserBalance.tenant_id == current_user.tenant_id
        ).first()
        
        if not balance:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Баланс не найден"
            )
        
        # Блокируем баланс для предотвращения race condition
        balance = db.query(UserBalance).filter(
            UserBalance.tenant_id == current_user.tenant_id
        ).with_for_update().first()
        
        if not balance:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Баланс не найден"
            )
        
        if balance.balance < amount:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Недостаточно средств на балансе"
            )
        
        # Списываем средства
        balance_before = balance.balance
        balance.balance -= amount
        balance.total_spent += amount
        
        # Создаем транзакцию списания
        transaction = BalanceTransaction(
            tenant_id=current_user.tenant_id,
            transaction_type="subscription_payment",
            amount=-amount,  # Отрицательная сумма для списания
            balance_before=balance_before,
            balance_after=balance.balance,
            description=f"Оплата подписки {subscription.plan.name}",
            reference_id=str(subscription.id)
        )
        db.add(transaction)
    
    # Отменяем старые активные подписки перед активацией новой
    db.query(Subscription).filter(
        and_(
            Subscription.tenant_id == current_user.tenant_id,
            Subscription.status == "active",
            Subscription.id != subscription_id  # Не отменяем ту, которую активируем
        )
    ).update({"status": "cancelled"})
    
    # Отменяем все другие подписки в статусе pending_payment
    db.query(Subscription).filter(
        and_(
            Subscription.tenant_id == current_user.tenant_id,
            Subscription.status == "pending_payment",
            Subscription.id != subscription_id  # Не отменяем ту, которую активируем
        )
    ).update({"status": "cancelled"})
    
    # Активируем подписку
    subscription.status = "active"
    subscription.started_at = datetime.utcnow()
    subscription.expires_at = datetime.utcnow() + timedelta(days=30)
    
    # Создаем запись об использовании
    now = datetime.utcnow()
    usage_record = UsageRecord(
        tenant_id=current_user.tenant_id,
        subscription_id=subscription.id,
        period_start=now,
        period_end=now + timedelta(days=30),
        notifications_sent=0,
        notifications_limit=subscription.plan.notifications_limit
    )
    db.add(usage_record)
    
    # Создаем запись о платеже
    payment = Payment(
        tenant_id=current_user.tenant_id,
        subscription_id=subscription.id,
        amount=amount,
        currency="RUB",
        status="completed",
        payment_method=payment_method,
        transaction_id=f"{payment_method.upper()}-{int(datetime.utcnow().timestamp())}",
        completed_at=datetime.utcnow()
    )
    db.add(payment)
    
    db.commit()
    db.refresh(subscription)
    
    return {"message": "Подписка успешно активирована", "subscription": subscription}

