from datetime import datetime

from fastapi import APIRouter, Depends, Path, Query
from fastapi.responses import JSONResponse
from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession

from api.depends import get_session, verify_admin_token


router = APIRouter()


@router.get("/all")
async def get_all_partners(
    limit: int = Query(1000, ge=1, le=10000, description="Лимит результатов"),
    offset: int = Query(0, ge=0, description="Смещение"),
    admin=Depends(verify_admin_token),
    session: AsyncSession = Depends(get_session),
):
    """Возвращает список всех партнёров со статистикой.

    Структура ответа:
    {
      "total": int,
      "items": [
        {
          "tg_id": int,
          "balance": float,
          "percent": float,
          "code": str | None,
          "method": str | None,
          "referred_count": int
        }
      ]
    }
    """

    partners_sql = text(
        """
        SELECT 
            p.partner_tg_id AS tg_id,
            COALESCE(u.partner_balance, 0) AS partner_balance,
            COALESCE(u.partner_percent, 0) AS partner_percent,
            u.partner_code,
            u.payout_method,
            COUNT(p.joined_tg_id) as joined_count
        FROM partners p
        LEFT JOIN users u ON u.tg_id = p.partner_tg_id
        WHERE p.partner_tg_id IS NOT NULL
        GROUP BY p.partner_tg_id, u.partner_balance, u.partner_percent, u.partner_code, u.payout_method
        ORDER BY partner_balance DESC
        LIMIT :limit OFFSET :offset
        """
    )

    count_sql = text(
        """
        SELECT COUNT(DISTINCT partner_tg_id) FROM partners
        WHERE partner_tg_id IS NOT NULL
        """
    )

    result = await session.execute(partners_sql, {"limit": limit, "offset": offset})
    partners = result.fetchall()

    count_result = await session.execute(count_sql)
    total = count_result.scalar() or 0

    partners_list = [
        {
            "tg_id": int(partner[0]),
            "balance": float(partner[1] or 0),
            "percent": float(partner[2] or 0),
            "code": partner[3] or None,
            "method": partner[4] or None,
            "referred_count": int(partner[5] or 0),
        }
        for partner in partners
    ]

    return JSONResponse(content={"total": total, "items": partners_list})


@router.get("/stats/all")
async def get_partners_stats(
    admin=Depends(verify_admin_token),
    session: AsyncSession = Depends(get_session),
):
    """Возвращает общую статистику партнёрской программы.

    Структура ответа:
    {
      "total_partners": int,
      "total_referred": int,
      "total_balance": float,
      "top_partner_tg_id": int,
      "top_partner_refs": int
    }
    """

    stats_sql = text(
        """
        WITH partner_refs AS (
            SELECT partner_tg_id, COUNT(DISTINCT joined_tg_id) AS ref_count
            FROM partners
            WHERE partner_tg_id IS NOT NULL
            GROUP BY partner_tg_id
        )
        SELECT 
            (SELECT COUNT(*) FROM partner_refs) AS total_partners,
            (SELECT COUNT(DISTINCT joined_tg_id) FROM partners WHERE partner_tg_id IS NOT NULL) AS total_referred,
            (
                SELECT COALESCE(SUM(u.partner_balance), 0.0)
                FROM users u
                WHERE u.tg_id IN (SELECT partner_tg_id FROM partner_refs)
            ) AS total_balance,
            (SELECT partner_tg_id FROM partner_refs ORDER BY ref_count DESC LIMIT 1) AS top_partner_tg_id,
            (SELECT ref_count FROM partner_refs ORDER BY ref_count DESC LIMIT 1) AS top_partner_refs
        """
    )

    stats_result = await session.execute(stats_sql)
    stats_row = stats_result.fetchone()

    if stats_row:
        stats = {
            "total_partners": int(stats_row[0] or 0),
            "total_referred": int(stats_row[1] or 0),
            "total_balance": float(stats_row[2] or 0.0),
            "top_partner_tg_id": int(stats_row[3] or 0),
            "top_partner_refs": int(stats_row[4] or 0),
        }
    else:
        stats = {
            "total_partners": 0,
            "total_referred": 0,
            "total_balance": 0.0,
            "top_partner_tg_id": 0,
            "top_partner_refs": 0,
        }

    return JSONResponse(content=stats)


@router.patch("/{tg_id}")
async def update_partner(
    tg_id: int = Path(..., description="Telegram ID партнёра"),
    balance: float = Query(..., description="Новый баланс партнёра"),
    percent: float = Query(..., description="Новый процент партнёра"),
    admin=Depends(verify_admin_token),
    session: AsyncSession = Depends(get_session),
):
    """Обновляет данные партнёра (баланс и процент).

    Структура ответа:
    {
      "success": bool,
      "message": str
    }
    """

    try:
        stmt = text(
            """
            UPDATE users 
            SET partner_balance = :balance, partner_percent = :percent 
            WHERE tg_id = :tg_id
            """
        )

        result = await session.execute(stmt, {"tg_id": tg_id, "balance": balance, "percent": percent})
        await session.commit()

        if result.rowcount > 0:
            return JSONResponse(
                content={"success": True, "message": f"Партнёр {tg_id} успешно обновлён"},
                status_code=200,
            )
        else:
            return JSONResponse(
                content={"success": False, "message": "Партнёр не найден"},
                status_code=404,
            )
    except Exception as e:
        await session.rollback()
        return JSONResponse(
            content={"success": False, "message": str(e)},
            status_code=500,
        )


@router.get("/{tg_id}")
async def get_partner_data(
    tg_id: int = Path(..., description="Telegram ID партнёра"),
    admin=Depends(verify_admin_token),
    session: AsyncSession = Depends(get_session),
):
    """Возвращает партнёрские данные для указанного `tg_id`.

    Структура ответа:
    {
      "tg_id": int,
      "partner_balance": float,
      "partner_percent": float,
      "partner_code": str | None,
      "payout_method": str | None,
      "invited": [
        { "tg_id": int, "joined_at": str | None, "balance": float, "subs_count": int, "payments_count": int }
      ]
    }
    """

    meta_sql = text(
        """
        SELECT 
            COALESCE(u.partner_balance, 0) AS partner_balance,
            COALESCE(u.partner_percent, 0) AS partner_percent,
            u.partner_code,
            u.payout_method
        FROM users u
        WHERE u.tg_id = :tg_id
        """
    )

    invited_sql = text(
        """
        SELECT 
            pr.joined_tg_id,
            pr.created_at,
            COALESCE(u.balance, 0) AS user_balance,
            (
                SELECT COUNT(*) FROM keys k 
                WHERE k.tg_id = pr.joined_tg_id
            ) AS subs_count,
            (
                SELECT COUNT(*) FROM payments pay 
                WHERE pay.tg_id = pr.joined_tg_id 
                  AND lower(pay.status) = 'success'
            ) AS payments_count
        FROM partners pr
        LEFT JOIN users u ON u.tg_id = pr.joined_tg_id
        WHERE pr.partner_tg_id = :tg_id
        ORDER BY pr.created_at DESC
        """
    )

    meta_res = await session.execute(meta_sql, {"tg_id": tg_id})
    meta_row = meta_res.fetchone()

    invited_res = await session.execute(invited_sql, {"tg_id": tg_id})
    invited_rows = invited_res.fetchall()

    response = {
        "tg_id": tg_id,
        "partner_balance": float(meta_row[0] or 0) if meta_row else 0.0,
        "partner_percent": float(meta_row[1] or 0) if meta_row else 0.0,
        "partner_code": meta_row[2] if meta_row else None,
        "payout_method": meta_row[3] if meta_row else None,
        "invited": [
            {
                "tg_id": row[0],
                "joined_at": row[1].isoformat() if isinstance(row[1], datetime) else None,
                "balance": float(row[2] or 0),
                "subs_count": int(row[3] or 0),
                "payments_count": int(row[4] or 0),
            }
            for row in invited_rows
        ],
    }

    return JSONResponse(content=response)


@router.get("/{tg_id}/invited")
async def get_partner_invited(
    tg_id: int = Path(..., description="Telegram ID партнёра"),
    admin=Depends(verify_admin_token),
    session: AsyncSession = Depends(get_session),
):
    """Возвращает список приглашённых пользователей конкретного партнёра.

    Структура ответа:
    [
      { "tg_id": int, "joined_at": str | None, "balance": float, "subs_count": int, "payments_count": int }
    ]
    """

    invited_sql = text(
        """
        SELECT 
            pr.joined_tg_id,
            pr.created_at,
            COALESCE(u.balance, 0) AS user_balance,
            (
                SELECT COUNT(*) FROM keys k 
                WHERE k.tg_id = pr.joined_tg_id
            ) AS subs_count,
            (
                SELECT COUNT(*) FROM payments pay 
                WHERE pay.tg_id = pr.joined_tg_id 
                  AND lower(pay.status) = 'success'
            ) AS payments_count
        FROM partners pr
        LEFT JOIN users u ON u.tg_id = pr.joined_tg_id
        WHERE pr.partner_tg_id = :tg_id
        ORDER BY pr.created_at DESC
        """
    )

    invited_res = await session.execute(invited_sql, {"tg_id": tg_id})
    invited_rows = invited_res.fetchall()

    invited_list = [
        {
            "tg_id": row[0],
            "joined_at": row[1].isoformat() if isinstance(row[1], datetime) else None,
            "balance": float(row[2] or 0),
            "subs_count": int(row[3] or 0),
            "payments_count": int(row[4] or 0),
        }
        for row in invited_rows
    ]

    return JSONResponse(content=invited_list)
