# plugins/admin/routes.py

from flask import (
    Blueprint, render_template, redirect, url_for,
    flash, request, jsonify
)
from flask_login import login_required, current_user
from flask_wtf.csrf import generate_csrf
from sqlalchemy import func, desc
from datetime import datetime, timedelta

from app import db
from plugins.auth.models import User, Invitation
from plugins.plant.growlog.models import GrowLog
from plugins.plant.models import Plant
from plugins.media.models import Media
from plugins.admin.models import AnalyticsEvent
from .forms import UserForm, AdjustInvitesForm

bp = Blueprint('admin', __name__, url_prefix='/admin', template_folder='templates')


@bp.route('/dashboard')
@login_required
def dashboard():
    if current_user.role != 'admin':
        return "Access denied", 403

    now       = datetime.utcnow()
    week_ago  = now - timedelta(days=7)
    month_ago = now - timedelta(days=30)

    # ─── Overview metrics ────────────────────────────────────────────── #

    # Users
    total_users     = User.query.count()
    active_users    = User.query.filter(
        User.is_deleted == False,
        User.is_banned == False,
        (User.suspended_until == None) | (User.suspended_until <= now)
    ).count()
    suspended_users = User.query.filter(User.suspended_until > now).count()
    banned_users    = User.query.filter_by(is_banned=True).count()
    deleted_users   = User.query.filter_by(is_deleted=True).count()
    new_7d_users    = User.query.filter(User.created_at >= week_ago).count()

    # Grow‐logs
    total_logs = GrowLog.query.count()
    logs_7d    = GrowLog.query.filter(GrowLog.created_at >= week_ago).count()

    # Sign‐ups last 30 days
    signup_dates  = [(month_ago + timedelta(days=i)).date() for i in range(31)]
    signup_counts = [
        User.query.filter(func.date(User.created_at) == d).count()
        for d in signup_dates
    ]
    chart_dates = [d.strftime('%Y-%m-%d') for d in signup_dates]

    # Status distribution
    role_counts = {
        'User':  User.query.filter_by(role='user').count(),
        'Admin': User.query.filter_by(role='admin').count()
    }

    # ─── Analytics aggregates ─────────────────────────────────────────── #

    ev_q      = AnalyticsEvent.query.filter(AnalyticsEvent.timestamp >= week_ago)
    total_ev  = ev_q.count() or 1
    error_ev  = ev_q.filter(AnalyticsEvent.status_code >= 500).count()
    error_pct = round(error_ev / total_ev * 100, 1)

    top_routes = [
        {'path': path, 'count': cnt}
        for path, cnt in db.session.query(
            AnalyticsEvent.path,
            func.count(AnalyticsEvent.id)
        )
        .filter(AnalyticsEvent.timestamp >= week_ago)
        .group_by(AnalyticsEvent.path)
        .order_by(desc(func.count(AnalyticsEvent.id)))
        .limit(10)
        .all()
    ]

    # Browser share
    browsers = {}
    ua_counts = (
        db.session.query(
            func.substr(AnalyticsEvent.user_agent, 1, 200).label('ua'),
            func.count(AnalyticsEvent.id).label('cnt')
        )
        .filter(AnalyticsEvent.user_agent.isnot(None))
        .filter(AnalyticsEvent.timestamp >= week_ago)
        .group_by(func.substr(AnalyticsEvent.user_agent, 1, 200))
        .all()
    )
    for ua, cnt in ua_counts:
        b = 'Other'
        if 'Chrome' in ua:
            b = 'Chrome'
        elif 'Firefox' in ua:
            b = 'Firefox'
        elif 'Safari' in ua and 'Chrome' not in ua:
            b = 'Safari'
        elif 'Edge' in ua:
            b = 'Edge'
        browsers[b] = browsers.get(b, 0) + cnt

    referrers = dict(
        db.session.query(
            AnalyticsEvent.referer, func.count(AnalyticsEvent.id)
        )
        .filter(AnalyticsEvent.referer.isnot(None))
        .filter(AnalyticsEvent.timestamp >= week_ago)
        .group_by(AnalyticsEvent.referer)
        .order_by(desc(func.count(AnalyticsEvent.id)))
        .limit(5)
        .all()
    )

    # ─── Stats metrics ────────────────────────────────────────────────── #

    total_plants   = Plant.query.count()
    total_images   = Media.query.count()
    active_plants  = Plant.query.filter_by(is_active=True).count()

    popular_plants = db.session.query(
        Plant.plant_type,
        func.count(Plant.id).label('count')
    ).filter(Plant.is_active == True) \
     .group_by(Plant.plant_type) \
     .order_by(desc('count')) \
     .limit(5) \
     .all()

    # ─── Render template ──────────────────────────────────────────────── #

    return render_template(
        'admin/dashboard.html',
        # Overview
        total_users=total_users,
        active_users=active_users,
        suspended_users=suspended_users,
        banned_users=banned_users,
        deleted_users=deleted_users,
        new_7d_users=new_7d_users,
        total_logs=total_logs,
        logs_7d=logs_7d,
        chart_dates=chart_dates,
        signup_counts=signup_counts,
        role_counts=role_counts,
        # Analytics
        error_pct=error_pct,
        top_routes=top_routes,
        browsers=browsers,
        referrers=referrers,
        # Stats
        total_plants=total_plants,
        total_images=total_images,
        active_plants=active_plants,
        popular_plants=popular_plants,
    )


@bp.route('/users')
@login_required
def list_users():
    if current_user.role != 'admin':
        return "Access denied", 403

    # --- parse query parameters ---
    page = request.args.get('page', 1, type=int)
    show_deleted = request.args.get('show_deleted', '0') == '1'
    q = request.args.get('q', '', type=str).strip()

    # --- build base query ---
    query = User.query
    if not show_deleted:
        query = query.filter_by(is_deleted=False)
    if q:
        like = f"%{q}%"
        query = query.filter(User.email.ilike(like))

    # --- paginate the results ---
    pagination = query.order_by(User.created_at.desc()) \
                      .paginate(page=page, per_page=25, error_out=False)
    users = pagination.items

    # --- AJAX response (JSON) ---
    if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
        token = generate_csrf()
        users_data = []
        for u in users:
            if u.is_banned:
                status = 'banned'
                until = None
            elif u.suspended_until and u.suspended_until > datetime.utcnow():
                status = 'suspended'
                until = u.suspended_until.strftime('%Y-%m-%d')
            else:
                status = 'active'
                until = None

            users_data.append({
                'id': u.id,
                'email': u.email,
                'role': u.role,
                'is_verified': u.is_verified,
                'excluded_from_analytics': u.excluded_from_analytics,
                'status': status,
                'suspended_until': until,
                'is_deleted': u.is_deleted,
                'created_at': u.created_at.strftime('%Y-%m-%d')
            })

        return jsonify({
            'users': users_data,
            'csrf_token': token
        })

    # --- normal HTML response ---
    return render_template(
        'admin/users/list.html',
        users=users,
        pagination=pagination,
        show_deleted=show_deleted,
        q=q
    )


@bp.route('/users/create', methods=['GET', 'POST'])
@login_required
def create_user():
    if current_user.role != 'admin':
        return "Access denied", 403
    form = UserForm()
    if form.validate_on_submit():
        u = User(
            email=form.email.data,
            role=form.role.data,
            is_verified=form.is_verified.data,
            excluded_from_analytics=form.excluded_from_analytics.data
        )
        # ban/suspend logic here if you need it...
        if form.password.data:
            u.set_password(form.password.data)
        db.session.add(u)
        db.session.commit()
        flash('User created.', 'success')
        return redirect(url_for('admin.list_users'))
    return render_template('admin/users/form.html', form=form, action='Create')


@bp.route('/users/<int:user_id>/edit', methods=['GET', 'POST'])
@login_required
def edit_user(user_id):
    if current_user.role != 'admin':
        return "Access denied", 403

    u = User.query.get_or_404(user_id)
    form = UserForm(obj=u)

    # Pre-populate on GET
    if request.method == 'GET':
        if u.is_banned:
            form.ban_type.data = 'perm'
        elif u.suspended_until and u.suspended_until > datetime.utcnow():
            form.ban_type.data = 'temp'
            days = (u.suspended_until - datetime.utcnow()).days
            form.suspend_days.data = days if days > 0 else 1
        else:
            form.ban_type.data = 'active'

    if form.validate_on_submit():
        u.email = form.email.data
        u.role = form.role.data
        u.is_verified = form.is_verified.data
        u.excluded_from_analytics = form.excluded_from_analytics.data

        # Ban/Suspend logic
        if form.ban_type.data == 'perm':
            u.is_banned = True
            u.suspended_until = None
        elif form.ban_type.data == 'temp':
            u.is_banned = False
            days = form.suspend_days.data or 7
            u.suspended_until = datetime.utcnow() + timedelta(days=days)
        else:
            u.is_banned = False
            u.suspended_until = None

        if form.password.data:
            u.set_password(form.password.data)

        db.session.commit()
        flash('User updated.', 'success')
        return redirect(url_for('admin.list_users',
                                page=request.args.get('page'),
                                show_deleted=request.args.get('show_deleted'),
                                q=request.args.get('q')))

    return render_template(
        'admin/users/form.html',
        form=form,
        action='Edit'
    )


@bp.route('/users/<int:user_id>/delete', methods=['POST'])
@login_required
def delete_user(user_id):
    if current_user.role != 'admin':
        return "Access denied", 403
    u = User.query.get_or_404(user_id)
    if u.id == current_user.id:
        flash("Cannot delete yourself.", 'warning')
    else:
        u.is_deleted = True
        db.session.commit()
        flash('User deleted (soft).', 'success')
    return redirect(url_for('admin.list_users',
                            page=request.args.get('page'),
                            show_deleted=request.args.get('show_deleted'),
                            q=request.args.get('q')))


@bp.route('/users/<int:user_id>/undelete', methods=['POST'])
@login_required
def undelete_user(user_id):
    if current_user.role != 'admin':
        return "Access denied", 403
    u = User.query.get_or_404(user_id)
    u.is_deleted = False
    db.session.commit()
    flash('User restored.', 'success')
    return redirect(url_for('admin.list_users',
                            page=request.args.get('page'),
                            show_deleted=request.args.get('show_deleted'),
                            q=request.args.get('q')))


@bp.route('/orphaned-media')
@login_required
def orphaned_media_list():
    if current_user.role != 'admin':
        return "Access denied", 403
    items = Media.query.filter_by(status='orphaned').order_by(Media.orphaned_at.desc()).all()
    return render_template('admin/orphaned_media_list.html', items=items)


# ─── Invitation Management ──────────────────────────────────────────────── #

@bp.route('/invitations')
@login_required
def list_invitations():
    if current_user.role != 'admin':
        return "Access denied", 403

    user_id = request.args.get('user_id', type=int)
    query = Invitation.query
    if user_id:
        query = query.filter(Invitation.created_by == user_id)
    invitations = query.order_by(Invitation.created_at.desc()).all()

    return render_template(
        'admin/invitations/list.html',
        invitations=invitations
    )

@bp.route('/users/<int:user_id>/adjust-invites', methods=['GET', 'POST'])
@login_required
def adjust_invites(user_id):
    if current_user.role != 'admin':
        return "Access denied", 403

    user = User.query.get_or_404(user_id)
    form = AdjustInvitesForm()

    if form.validate_on_submit():
        # Apply the delta and ensure invites_remaining never goes below zero
        user.invites_remaining = max(0, user.invites_remaining + form.delta.data)
        db.session.commit()
        flash('Invitation quota updated successfully.', 'success')
        return redirect(url_for('admin.list_users'))

    return render_template(
        'admin/invitations/adjust_invites.html',
        user=user,
        form=form
    )
