import uuid

from fastapi import APIRouter, File, Query, UploadFile

from app.api.deps import AdminDep, PageDep, SessionDep, UserDep
from app.api.serializers import dump, dump_list
from app.core.exceptions import ValidationError
from app.core.response import paginated, success
from app.models import PaymentMethod, PaymentStatus
from app.schemas import ManualPaymentAction, OrderOut, PaymentCreate, PaymentOut
from app.services import OrderService, PaymentMonitor, PaymentService, SettingsService, UploadService

router = APIRouter(tags=["payments"])


@router.post("/payments")
async def create_payment(payload: PaymentCreate, user: UserDep, session: SessionDep) -> dict:
    """Single entry point for every product: wallet, TRON invoice or bank transfer."""
    orders = OrderService(session)
    service = PaymentService(session)
    order = await orders.get_for_user(payload.order_id, user.id)

    if payload.method == PaymentMethod.WALLET:
        order = await service.pay_with_wallet(order)
        return success({"order": dump(OrderOut, order), "payment": None}, "payment_completed")

    if payload.method == PaymentMethod.TRON:
        payment = await service.create_tron_invoice(order)
        return success(
            {"order": dump(OrderOut, order), "payment": dump(PaymentOut, payment)},
            "invoice_created",
        )

    settings_service = SettingsService(session)
    card_number = await settings_service.get_str("bank_card_number")
    if not card_number:
        raise ValidationError("bank_not_configured")
    payment = await service.create_bank_payment(order)
    return success(
        {
            "order": dump(OrderOut, order),
            "payment": dump(PaymentOut, payment),
            "card_number": card_number,
            "card_owner": await settings_service.get_str("bank_card_owner"),
        },
        "bank_payment_created",
    )


@router.get("/payments/{payment_id}")
async def get_payment(payment_id: uuid.UUID, user: UserDep, session: SessionDep) -> dict:
    service = PaymentService(session)
    payment = await service.get(payment_id)
    order = await OrderService(session).get_for_user(payment.order_id, user.id)
    return success({"payment": dump(PaymentOut, payment), "order": dump(OrderOut, order)})


@router.post("/payments/{payment_id}/check")
async def check_payment(payment_id: uuid.UUID, user: UserDep, session: SessionDep) -> dict:
    """The bot's 'check payment' button: verify one TRON invoice on demand."""
    service = PaymentService(session)
    payment = await service.get(payment_id)
    order = await OrderService(session).get_for_user(payment.order_id, user.id)

    if payment.status == PaymentStatus.PAID:
        return success({"paid": True, "order": dump(OrderOut, order)})

    if payment.status == PaymentStatus.EXPIRED:
        return success({"paid": False, "expired": True, "order": dump(OrderOut, order)})

    paid = await PaymentMonitor(session).verify_single(payment)
    order = await OrderService(session).get(payment.order_id)
    return success({"paid": paid, "expired": False, "order": dump(OrderOut, order)})


@router.post("/payments/{payment_id}/receipt")
async def upload_receipt(
    payment_id: uuid.UUID,
    user: UserDep,
    session: SessionDep,
    file: UploadFile = File(...),
) -> dict:
    service = PaymentService(session)
    payment = await service.get(payment_id)
    await OrderService(session).get_for_user(payment.order_id, user.id)

    stored = await UploadService().save_image(file, folder="receipts")
    payment = await service.attach_receipt(payment, stored["path"])
    return success(dump(PaymentOut, payment), "receipt_uploaded")


# -- admin ----------------------------------------------------------
@router.get("/admin/payments")
async def admin_list_payments(
    session: SessionDep,
    _: AdminDep,
    page_params: PageDep,
    status: str | None = Query(default=None),
    method: str | None = Query(default=None),
) -> dict:
    items, total = await PaymentService(session).search(
        page_params.page, page_params.size, status=status, method=method
    )
    return success(
        paginated(dump_list(PaymentOut, items), total, page_params.page, page_params.size)
    )


@router.get("/admin/payments/{payment_id}")
async def admin_get_payment(payment_id: uuid.UUID, session: SessionDep, _: AdminDep) -> dict:
    service = PaymentService(session)
    payment = await service.get(payment_id)
    order = await OrderService(session).get(payment.order_id)
    return success({"payment": dump(PaymentOut, payment), "order": dump(OrderOut, order)})


@router.post("/admin/payments/{payment_id}/approve")
async def approve_payment(
    payment_id: uuid.UUID, payload: ManualPaymentAction, session: SessionDep, _: AdminDep
) -> dict:
    order = await PaymentService(session).approve_manual_payment(payment_id, payload.note or "")
    return success(dump(OrderOut, order), "payment_approved")


@router.post("/admin/payments/{payment_id}/reject")
async def reject_payment(
    payment_id: uuid.UUID, payload: ManualPaymentAction, session: SessionDep, _: AdminDep
) -> dict:
    payment = await PaymentService(session).reject_manual_payment(payment_id, payload.note or "")
    return success(dump(PaymentOut, payment), "payment_rejected")


@router.post("/admin/payments/check-tron")
async def admin_check_tron(session: SessionDep, _: AdminDep) -> dict:
    matched = await PaymentMonitor(session).check_tron_payments()
    return success({"matched": matched}, "tron_checked")
