import os
import uuid
import httpx
from datetime import datetime, timedelta, timezone

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload
from yookassa import Configuration, Payment
from core.rabbitmq import publish_ticket_task
from api.deps import get_current_user
from database.models import Seat, Ticket, TicketStatus, User
from database.session import get_db
from schemas.ticket import (
    TicketResponse, 
    TicketScanRequest, 
    TicketScanResponse,
    TicketBookRequest,
    TicketBookResponse,
    YookassaWebhook
)

# Если у тебя есть готовая функция для Раббита, раскомментируй импорт (путь может отличаться)
# from core.rabbitmq import publish_ticket_task 

router = APIRouter(prefix="/api/tickets", tags=["tickets"])

@router.get("/me", response_model=list[TicketResponse])
async def get_my_tickets(
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
) -> list[Ticket]:
    """Возвращает все оплаченные билеты текущего пользователя."""
    result = await db.execute(
        select(Ticket)
        .where(Ticket.user_id == current_user.id, Ticket.status == TicketStatus.PAID)
        .options(selectinload(Ticket.seat).selectinload(Seat.tournament))
        .order_by(Ticket.created_at.desc())
    )
    return list(result.scalars().all())


@router.post("/scan", response_model=TicketScanResponse)
async def scan_ticket(
    body: TicketScanRequest,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
) -> TicketScanResponse:
    """Сканирует билет по secret_token (QR-код)."""
    result = await db.execute(select(Ticket).where(Ticket.secret_token == body.token))
    ticket: Ticket | None = result.scalar_one_or_none()

    if ticket is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=TicketScanResponse(success=False, message="Билет не найден или подделка").model_dump(),
        )
    if ticket.status == TicketStatus.SCANNED:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=TicketScanResponse(success=False, message="Билет уже отсканирован!", ticket_id=ticket.id).model_dump(),
        )
    if ticket.status != TicketStatus.PAID:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=TicketScanResponse(success=False, message=f"Проход запрещен: статус билета '{ticket.status.value}'", ticket_id=ticket.id).model_dump(),
        )

    ticket.status = TicketStatus.SCANNED
    await db.commit()
    return TicketScanResponse(success=True, message="Проход разрешен", ticket_id=ticket.id)


@router.post("/book", response_model=TicketBookResponse)
async def book_ticket(
    body: TicketBookRequest,
    current_user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    """Блокирует место на 15 минут и генерирует ссылку на оплату."""
    seat_query = await db.execute(
        select(Seat).options(selectinload(Seat.tournament)).where(Seat.id == body.seat_id)
    )
    seat = seat_query.scalar_one_or_none()
    if not seat:
        raise HTTPException(status_code=404, detail="Место не найдено")

    ticket_query = await db.execute(select(Ticket).where(Ticket.seat_id == seat.id))
    existing_ticket = ticket_query.scalar_one_or_none()
    now = datetime.now(timezone.utc)

    # Проверка блокировок
    if existing_ticket:
        if existing_ticket.status == TicketStatus.PAID:
            raise HTTPException(status_code=400, detail="Место уже выкуплено")
        if existing_ticket.status == TicketStatus.LOCKED and existing_ticket.expires_at and existing_ticket.expires_at > now:
            if existing_ticket.user_id != current_user.id:
                raise HTTPException(status_code=400, detail="Место временно забронировано другим пользователем")

    description = f"Билет: {seat.tournament.title}, Сектор {seat.sector}, Ряд {seat.row}, Место {seat.number}"[:128] 
    shop_id = os.getenv("YOOKASSA_SHOP_ID", "dummy")
    
    if shop_id == "test_shop":
        # Стучимся в наш мок-сервер
        mock_url = os.getenv("MOCK_API_URL", "http://192.168.149.101:8083/v3/payments")
        async with httpx.AsyncClient() as client:
            response = await client.post(
                mock_url,
                json={
                    "amount": {"value": f"{seat.price}.00", "currency": "RUB"},
                    "confirmation": {"type": "redirect", "return_url": "https://openticket.artifitial.ru/tickets"},
                    "capture": True,
                    "description": description
                },
                headers={"Idempotence-Key": str(uuid.uuid4())}
            )
            response.raise_for_status()
            payment_data = response.json()
            payment_id = payment_data["id"]
            payment_url = payment_data["confirmation"]["confirmation_url"]
            
    else:
        # Реальная ЮKassa
        Configuration.account_id = shop_id
        Configuration.secret_key = os.getenv("YOOKASSA_SECRET_KEY")
        payment = Payment.create({
            "amount": {"value": f"{seat.price}.00", "currency": "RUB"},
            "confirmation": {"type": "redirect", "return_url": "https://openticket.artifitial.ru/tickets"},
            "capture": True,
            "description": description
        }, str(uuid.uuid4()))
        payment_id = payment.id
        payment_url = payment.confirmation.confirmation_url

    # Фиксируем бронь
    if not existing_ticket:
        ticket = Ticket(
            seat_id=seat.id,
            user_id=current_user.id,
            status=TicketStatus.LOCKED,
            payment_id=payment_id,
            payment_url=payment_url,
            expires_at=now + timedelta(minutes=15)
        )
        db.add(ticket)
    else:
        existing_ticket.user_id = current_user.id
        existing_ticket.status = TicketStatus.LOCKED
        existing_ticket.payment_id = payment_id
        existing_ticket.payment_url = payment_url
        existing_ticket.expires_at = now + timedelta(minutes=15)
        ticket = existing_ticket

    await db.commit()

    return TicketBookResponse(ticket_id=ticket.id, payment_url=payment_url)


@router.post("/webhook/yookassa")
async def yookassa_webhook(
    payload: YookassaWebhook,
    db: AsyncSession = Depends(get_db)
):
    """Принимает уведомления от платежного шлюза."""
    query = await db.execute(select(Ticket).where(Ticket.payment_id == payload.object.id))
    ticket = query.scalar_one_or_none()

    if not ticket:
        return {"status": "ignored", "reason": "ticket not found"}

    if payload.event == "payment.succeeded" and payload.object.status == "succeeded":
        if ticket.status != TicketStatus.PAID:
            ticket.status = TicketStatus.PAID
            await db.commit()
            
            # ---> ЗДЕСЬ ПУШИМ ЗАДАЧУ В RABBITMQ <---
            # Если у тебя есть функция публикации:
            # ...
            ticket.status = TicketStatus.PAID
            await db.commit()
            
            # Отправляем в очередь
            await publish_ticket_task(ticket.id)
            # ...
            print(f"Оплата получена. Задача на PDF для билета {ticket.id} отправлена в очередь.")

    elif payload.event == "payment.canceled":
        if ticket.status == TicketStatus.LOCKED:
            await db.delete(ticket)
            await db.commit()

    return {"status": "ok"}