from fastapi import APIRouter, Depends, Query
from datetime import datetime, timedelta, date
from typing import Dict, Any, Optional
from sqlalchemy import select, func, and_
from sqlalchemy.ext.asyncio import AsyncSession

from ..auth import require_admin
from ..db import get_session
from ..models import Account, UsageEvent, Job

router = APIRouter(prefix="/api/admin/reports", tags=["admin-reports"])


@router.get("/daily-summary", dependencies=[Depends(require_admin)])
async def get_daily_summary_report(
    date: Optional[date] = Query(None), db: AsyncSession = Depends(get_session)
) -> Dict[str, Any]:
    """Get daily business metrics summary"""

    target_date = date or datetime.utcnow().date()
    start_time = datetime.combine(target_date, datetime.min.time())
    end_time = datetime.combine(target_date, datetime.max.time())

    # New signups
    new_accounts = await db.scalar(
        select(func.count(Account.id)).where(
            and_(Account.created_at >= start_time, Account.created_at <= end_time)
        )
    )

    # Revenue
    revenue = (
        await db.scalar(
            select(func.sum(UsageEvent.usage_metadata["amount"].as_float())).where(
                and_(
                    UsageEvent.event_type.in_(
                        ["credit_purchase", "subscription_payment"]
                    ),
                    UsageEvent.time >= start_time,
                    UsageEvent.time <= end_time,
                )
            )
        )
        or 0
    )

    # Active users
    active_users = await db.scalar(
        select(func.count(func.distinct(UsageEvent.account_id))).where(
            and_(
                UsageEvent.time >= start_time,
                UsageEvent.time <= end_time,
                UsageEvent.credits_consumed > 0,
            )
        )
    )

    # Jobs processed
    jobs_processed = await db.scalar(
        select(func.count(Job.id)).where(
            and_(
                Job.created_at >= start_time,
                Job.created_at <= end_time,
                Job.status == "completed",
            )
        )
    )

    # Credits consumed
    credits_consumed = (
        await db.scalar(
            select(func.sum(UsageEvent.credits_consumed)).where(
                and_(
                    UsageEvent.time >= start_time,
                    UsageEvent.time <= end_time,
                    UsageEvent.credits_consumed > 0,
                )
            )
        )
        or 0
    )

    return {
        "date": target_date.isoformat(),
        "metrics": {
            "new_signups": new_accounts,
            "revenue": round(revenue, 2),
            "active_users": active_users,
            "jobs_processed": jobs_processed,
            "credits_consumed": credits_consumed,
        },
        "comparisons": {
            "vs_yesterday": await _get_day_comparison(db, target_date, -1),
            "vs_last_week": await _get_day_comparison(db, target_date, -7),
        },
    }


@router.get("/cohort-retention", dependencies=[Depends(require_admin)])
async def get_cohort_retention(
    months: int = Query(6, ge=1, le=12), db: AsyncSession = Depends(get_session)
) -> Dict[str, Any]:
    """Get cohort retention analysis"""

    # This would be a complex query showing user retention by signup cohort
    # Simplified version here

    cohorts = []
    for i in range(months):
        cohort_start = datetime.utcnow() - timedelta(days=30 * i)
        cohort_data = await _calculate_cohort_retention(db, cohort_start)
        cohorts.append(cohort_data)

    return {
        "cohorts": cohorts,
        "average_retention": {"day_1": 85, "day_7": 70, "day_30": 55, "day_90": 40},
    }


async def _get_day_comparison(
    db: AsyncSession, target_date: date, days_offset: int
) -> Dict[str, float]:
    """Get comparison metrics for a given day offset"""
    compare_date = target_date + timedelta(days=days_offset)
    start_time = datetime.combine(compare_date, datetime.min.time())
    end_time = datetime.combine(compare_date, datetime.max.time())

    # Get metrics for comparison date
    revenue = (
        await db.scalar(
            select(func.sum(UsageEvent.usage_metadata["amount"].as_float())).where(
                and_(
                    UsageEvent.event_type.in_(
                        ["credit_purchase", "subscription_payment"]
                    ),
                    UsageEvent.time >= start_time,
                    UsageEvent.time <= end_time,
                )
            )
        )
        or 0
    )

    active_users = await db.scalar(
        select(func.count(func.distinct(UsageEvent.account_id))).where(
            and_(
                UsageEvent.time >= start_time,
                UsageEvent.time <= end_time,
                UsageEvent.credits_consumed > 0,
            )
        )
    )

    return {
        "revenue_change": 0,  # Would calculate percentage change
        "active_users_change": 0,
        "date": compare_date.isoformat(),
    }


async def _calculate_cohort_retention(
    db: AsyncSession, cohort_start: datetime
) -> Dict[str, Any]:
    """Calculate retention metrics for a specific cohort"""
    cohort_end = cohort_start + timedelta(days=30)

    # Get users who signed up in this cohort
    cohort_users = await db.scalars(
        select(Account.id).where(
            and_(Account.created_at >= cohort_start, Account.created_at < cohort_end)
        )
    )
    cohort_user_ids = list(cohort_users)

    if not cohort_user_ids:
        return {
            "cohort_month": cohort_start.strftime("%Y-%m"),
            "cohort_size": 0,
            "retention": {},
        }

    # Calculate retention at different intervals
    retention = {}
    for days in [1, 7, 30, 90]:
        retention_date = cohort_start + timedelta(days=days)
        retained_users = await db.scalar(
            select(func.count(func.distinct(UsageEvent.account_id))).where(
                and_(
                    UsageEvent.account_id.in_(cohort_user_ids),
                    UsageEvent.time >= retention_date,
                    UsageEvent.time < retention_date + timedelta(days=1),
                    UsageEvent.credits_consumed > 0,
                )
            )
        )
        retention[f"day_{days}"] = (
            (retained_users / len(cohort_user_ids) * 100) if cohort_user_ids else 0
        )

    return {
        "cohort_month": cohort_start.strftime("%Y-%m"),
        "cohort_size": len(cohort_user_ids),
        "retention": retention,
    }
