"""
Admin domain: role-gated admin panel for managing users, tasks, etc.
"""
from datetime import datetime, timedelta
from functools import wraps
from pathlib import Path

from quart import Blueprint, flash, g, redirect, render_template, request, session, url_for

from ..core import csrf_protect, execute, fetch_all, fetch_one

# Blueprint with its own template folder
bp = Blueprint(
    "admin",
    __name__,
    template_folder=str(Path(__file__).parent / "templates"),
    url_prefix="/admin",
)


# =============================================================================
# SQL Queries
# =============================================================================

async def get_dashboard_stats() -> dict:
    """Get admin dashboard statistics."""
    now = datetime.utcnow()
    today = now.date().isoformat()
    week_ago = (now - timedelta(days=7)).isoformat()

    users_total = await fetch_one("SELECT COUNT(*) as count FROM users WHERE deleted_at IS NULL")
    users_today = await fetch_one(
        "SELECT COUNT(*) as count FROM users WHERE created_at >= ? AND deleted_at IS NULL",
        (today,),
    )
    users_week = await fetch_one(
        "SELECT COUNT(*) as count FROM users WHERE created_at >= ? AND deleted_at IS NULL",
        (week_ago,),
    )

    subs = await fetch_one(
        "SELECT COUNT(*) as count FROM subscriptions WHERE status = 'active'"
    )

    tasks_pending = await fetch_one("SELECT COUNT(*) as count FROM tasks WHERE status = 'pending'")
    tasks_failed = await fetch_one("SELECT COUNT(*) as count FROM tasks WHERE status = 'failed'")

    waitlist_count = await fetch_one("SELECT COUNT(*) as count FROM waitlist")
    feedback_unread = await fetch_one(
        "SELECT COUNT(*) as count FROM feedback WHERE is_read = 0"
    )

    # Analytics stats (DuckDB)
    analytics = {"commodity_count": 0, "min_year": None, "max_year": None}
    try:
        from ..analytics import _db_path, fetch_analytics

        if _db_path:
            rows = await fetch_analytics(
                """
                SELECT COUNT(DISTINCT commodity_code) as commodity_count,
                       MIN(market_year) as min_year,
                       MAX(market_year) as max_year
                FROM serving.commodity_metrics
                WHERE country_code IS NOT NULL
                """
            )
            if rows:
                analytics = rows[0]
    except Exception:
        pass

    return {
        "users_total": users_total["count"] if users_total else 0,
        "users_today": users_today["count"] if users_today else 0,
        "users_week": users_week["count"] if users_week else 0,
        "active_subscriptions": subs["count"] if subs else 0,
        "tasks_pending": tasks_pending["count"] if tasks_pending else 0,
        "tasks_failed": tasks_failed["count"] if tasks_failed else 0,
        "waitlist_count": waitlist_count["count"] if waitlist_count else 0,
        "feedback_unread": feedback_unread["count"] if feedback_unread else 0,
        "commodity_count": analytics.get("commodity_count", 0),
        "data_year_range": f"{analytics.get('min_year', '?')}–{analytics.get('max_year', '?')}",
    }


async def get_users(limit: int = 50, offset: int = 0, search: str = None) -> list[dict]:
    """Get users with optional search."""
    if search:
        return await fetch_all(
            """
            SELECT u.*, s.plan, s.status as sub_status
            FROM users u
            LEFT JOIN subscriptions s ON s.user_id = u.id AND s.status = 'active'
            WHERE u.deleted_at IS NULL AND u.email LIKE ?
            ORDER BY u.created_at DESC
            LIMIT ? OFFSET ?
            """,
            (f"%{search}%", limit, offset)
        )
    return await fetch_all(
        """
        SELECT u.*, s.plan, s.status as sub_status
        FROM users u
        LEFT JOIN subscriptions s ON s.user_id = u.id AND s.status = 'active'
        WHERE u.deleted_at IS NULL
        ORDER BY u.created_at DESC
        LIMIT ? OFFSET ?
        """,
        (limit, offset)
    )


async def get_user_by_id(user_id: int) -> dict | None:
    """Get user by ID with subscription info."""
    return await fetch_one(
        """
        SELECT u.*, s.plan, s.status as sub_status
        FROM users u
        LEFT JOIN subscriptions s ON s.user_id = u.id
        WHERE u.id = ?
        """,
        (user_id,)
    )


async def get_recent_tasks(limit: int = 50) -> list[dict]:
    """Get recent tasks."""
    return await fetch_all(
        """
        SELECT * FROM tasks
        ORDER BY created_at DESC
        LIMIT ?
        """,
        (limit,)
    )


async def get_failed_tasks() -> list[dict]:
    """Get failed tasks."""
    return await fetch_all(
        "SELECT * FROM tasks WHERE status = 'failed' ORDER BY created_at DESC"
    )


async def retry_task(task_id: int) -> bool:
    """Retry a failed task."""
    result = await execute(
        """
        UPDATE tasks 
        SET status = 'pending', run_at = ?, error = NULL
        WHERE id = ? AND status = 'failed'
        """,
        (datetime.utcnow().isoformat(), task_id)
    )
    return result > 0


async def delete_task(task_id: int) -> bool:
    """Delete a task."""
    result = await execute("DELETE FROM tasks WHERE id = ?", (task_id,))
    return result > 0


async def get_feedback(limit: int = 100) -> list[dict]:
    """Get feedback with user email joined."""
    return await fetch_all(
        """
        SELECT f.*, u.email as user_email
        FROM feedback f
        LEFT JOIN users u ON u.id = f.user_id
        ORDER BY f.is_read ASC, f.created_at DESC
        LIMIT ?
        """,
        (limit,)
    )


async def get_waitlist(limit: int = 500) -> list[dict]:
    """Get waitlist entries."""
    return await fetch_all(
        "SELECT * FROM waitlist ORDER BY created_at DESC LIMIT ?",
        (limit,)
    )


# =============================================================================
# Decorators
# =============================================================================

def admin_required(f):
    """Require the user to have the 'admin' role (granted via ADMIN_EMAILS or user_roles table)."""
    @wraps(f)
    async def decorated(*args, **kwargs):
        if "admin" not in (g.get("user") or {}).get("roles", []):
            await flash("Admin access required.", "error")
            return redirect(url_for("auth.login"))
        return await f(*args, **kwargs)
    return decorated


# =============================================================================
# Routes
# =============================================================================

@bp.route("/logout", methods=["POST"])
@csrf_protect
async def logout():
    """Log out from admin (clears full session)."""
    session.clear()
    await flash("Logged out.", "info")
    return redirect(url_for("auth.login"))


@bp.route("/")
@admin_required
async def index():
    """Admin dashboard."""
    stats = await get_dashboard_stats()
    recent_users = await get_users(limit=10)
    failed_tasks = await get_failed_tasks()
    
    return await render_template(
        "admin/index.html",
        stats=stats,
        recent_users=recent_users,
        failed_tasks=failed_tasks,
    )


@bp.route("/users")
@admin_required
async def users():
    """User list."""
    search = request.args.get("search", "").strip()
    page = int(request.args.get("page", 1))
    per_page = 50
    offset = (page - 1) * per_page
    
    user_list = await get_users(limit=per_page, offset=offset, search=search or None)
    
    return await render_template(
        "admin/users.html",
        users=user_list,
        search=search,
        page=page,
    )


@bp.route("/users/<int:user_id>")
@admin_required
async def user_detail(user_id: int):
    """User detail page."""
    user = await get_user_by_id(user_id)
    if not user:
        await flash("User not found.", "error")
        return redirect(url_for("admin.users"))
    
    return await render_template("admin/user_detail.html", user=user)


@bp.route("/users/<int:user_id>/impersonate", methods=["POST"])
@admin_required
@csrf_protect
async def impersonate(user_id: int):
    """Impersonate a user (login as them)."""
    user = await get_user_by_id(user_id)
    if not user:
        await flash("User not found.", "error")
        return redirect(url_for("admin.users"))
    
    # Store admin's user_id so we can restore it later
    session["admin_impersonating"] = session.get("user_id")
    session["user_id"] = user_id
    
    await flash(f"Now impersonating {user['email']}. Return to admin to stop.", "warning")
    return redirect(url_for("dashboard.index"))


@bp.route("/stop-impersonating", methods=["POST"])
@csrf_protect
async def stop_impersonating():
    """Stop impersonating and return to admin."""
    admin_user_id = session.pop("admin_impersonating", None)
    if admin_user_id:
        session["user_id"] = admin_user_id
    else:
        session.pop("user_id", None)
    await flash("Stopped impersonating.", "info")
    return redirect(url_for("admin.index"))


@bp.route("/tasks")
@admin_required
async def tasks():
    """Task queue management."""
    task_list = await get_recent_tasks(limit=100)
    failed = await get_failed_tasks()
    
    return await render_template(
        "admin/tasks.html",
        tasks=task_list,
        failed_tasks=failed,
    )


@bp.route("/tasks/<int:task_id>/retry", methods=["POST"])
@admin_required
@csrf_protect
async def task_retry(task_id: int):
    """Retry a failed task."""
    success = await retry_task(task_id)
    if success:
        await flash("Task queued for retry.", "success")
    else:
        await flash("Could not retry task.", "error")
    return redirect(url_for("admin.tasks"))


@bp.route("/tasks/<int:task_id>/delete", methods=["POST"])
@admin_required
@csrf_protect
async def task_delete(task_id: int):
    """Delete a task."""
    success = await delete_task(task_id)
    if success:
        await flash("Task deleted.", "success")
    else:
        await flash("Could not delete task.", "error")
    return redirect(url_for("admin.tasks"))


@bp.route("/feedback")
@admin_required
async def feedback():
    """Feedback viewer."""
    items = await get_feedback()
    unread_count = sum(1 for f in items if not f["is_read"])

    return await render_template(
        "admin/feedback.html",
        feedback_items=items,
        unread_count=unread_count,
    )


@bp.route("/feedback/<int:feedback_id>/mark-read", methods=["POST"])
@admin_required
@csrf_protect
async def feedback_mark_read(feedback_id: int):
    """Mark a feedback item as read."""
    await execute(
        "UPDATE feedback SET is_read = 1 WHERE id = ?",
        (feedback_id,)
    )
    return redirect(url_for("admin.feedback"))


@bp.route("/waitlist")
@admin_required
async def waitlist():
    """Waitlist admin view."""
    entries = await get_waitlist()

    return await render_template(
        "admin/waitlist.html",
        entries=entries,
        total=len(entries),
    )


# =============================================================================
# Feature Flags
# =============================================================================

@bp.route("/flags")
@admin_required
async def flags():
    """Feature flags admin."""
    flag_list = await fetch_all("SELECT * FROM feature_flags ORDER BY name")
    return await render_template("admin/flags.html", flags=flag_list)


@bp.route("/flags/create", methods=["POST"])
@admin_required
@csrf_protect
async def flag_create():
    """Create a feature flag."""
    form = await request.form
    name = (form.get("name") or "").strip().lower().replace(" ", "_")
    description = (form.get("description") or "").strip()
    if not name:
        await flash("Flag name is required.", "error")
        return redirect(url_for("admin.flags"))
    await execute(
        "INSERT OR IGNORE INTO feature_flags (name, enabled, description, updated_at) VALUES (?, 0, ?, ?)",
        (name, description or None, datetime.utcnow().isoformat()),
    )
    await flash(f"Flag '{name}' created.", "success")
    return redirect(url_for("admin.flags"))


@bp.route("/flags/toggle", methods=["POST"])
@admin_required
@csrf_protect
async def flag_toggle():
    """Toggle a feature flag on/off."""
    form = await request.form
    name = (form.get("name") or "").strip()
    await execute(
        "UPDATE feature_flags SET enabled = NOT enabled, updated_at = ? WHERE name = ?",
        (datetime.utcnow().isoformat(), name),
    )
    return redirect(url_for("admin.flags"))


# =============================================================================
# Email Log
# =============================================================================

@bp.route("/emails")
@admin_required
async def emails():
    """Email log admin."""
    log = await fetch_all(
        "SELECT * FROM email_log ORDER BY created_at DESC LIMIT 500"
    )
    return await render_template("admin/emails.html", log=log)
