"""
app/admin/routes.py
--------------------
Everything a club admin can do: create competitions, view entries, generate
the random draw, adjust it, finalize it, and resolve disputes.

This file is intentionally the "thicker" of the two role blueprints, since
admins have the most functionality. If it grows too large later, it can be
split (e.g. admin/competitions.py, admin/draws.py, admin/disputes.py) — the
routes themselves won't need to change, just which file they live in.
"""

import random
from datetime import datetime

from flask import Blueprint, render_template, redirect, url_for, flash, request
from flask_login import login_required, current_user

from app.extensions import db
from app.models import (
    User, CompetitionTemplate, Competition, Entry, Draw, Match, Dispute
)
from app.admin.decorators import admin_required

admin_bp = Blueprint("admin", __name__, template_folder="../templates/admin")


@admin_bp.route("/")
@login_required
@admin_required
def dashboard():
    """Landing page for admins: a quick summary + links into everything else."""
    competitions = Competition.query.order_by(Competition.created_at.desc()).all()
    open_disputes = Dispute.query.filter_by(status="open").count()
    return render_template("admin/dashboard.html", competitions=competitions, open_disputes=open_disputes)


# ---------------------------------------------------------------------------
# Competitions (Stage 1: setup + registration)
# ---------------------------------------------------------------------------

@admin_bp.route("/competitions/new", methods=["GET", "POST"])
@login_required
@admin_required
def new_competition():
    """
    Create a new Competition from one of the preconfigured
    CompetitionTemplates (Matchplay Singles - Men, etc.)
    """
    templates = CompetitionTemplate.query.all()

    if request.method == "POST":
        competition = Competition(
            template_id=request.form.get("template_id"),
            registration_opens=datetime.strptime(request.form["registration_opens"], "%Y-%m-%d").date(),
            registration_closes=datetime.strptime(request.form["registration_closes"], "%Y-%m-%d").date(),
            competition_starts=datetime.strptime(request.form["competition_starts"], "%Y-%m-%d").date(),
            competition_ends=datetime.strptime(request.form["competition_ends"], "%Y-%m-%d").date(),
            entry_fee=float(request.form.get("entry_fee") or 0),
            manager_name=request.form.get("manager_name"),
            manager_contact=request.form.get("manager_contact"),
            stage="registration",
        )
        db.session.add(competition)
        db.session.commit()
        flash("Competition created. The signup form is now available to members.", "success")
        return redirect(url_for("admin.view_competition", competition_id=competition.id))

    return render_template("admin/new_competition.html", templates=templates)


@admin_bp.route("/competitions/<int:competition_id>")
@login_required
@admin_required
def view_competition(competition_id):
    """Shows a competition's entries, current stage, and the draw once generated."""
    competition = Competition.query.get_or_404(competition_id)
    draw = Draw.query.filter_by(competition_id=competition.id).order_by(Draw.generated_date.desc()).first()
    return render_template("admin/view_competition.html", competition=competition, draw=draw)


# ---------------------------------------------------------------------------
# Stage 2: the random draw
# ---------------------------------------------------------------------------

@admin_bp.route("/competitions/<int:competition_id>/generate-draw", methods=["POST"])
@login_required
@admin_required
def generate_draw(competition_id):
    """
    Randomly shuffles all entries and pairs them off into first-round
    matches. If there's an odd number of entries, the last one gets a
    "bye" (an automatic walkover into the next round).

    This creates a new Draw with is_finalized=False, so the admin gets a
    chance to review/adjust before it's issued to players (see
    finalize_draw below).
    """
    competition = Competition.query.get_or_404(competition_id)
    entries = Entry.query.filter_by(competition_id=competition.id).all()

    if len(entries) < 2:
        flash("Need at least 2 entries to generate a draw.", "error")
        return redirect(url_for("admin.view_competition", competition_id=competition.id))

    shuffled = entries[:]  # copy so we don't mutate the original query result
    random.shuffle(shuffled)

    draw = Draw(competition_id=competition.id)
    db.session.add(draw)
    db.session.flush()  # assigns draw.id without needing a full commit yet

    # Pair entries two at a time. If odd, the final entry gets a bye
    # (entry2 left as None; Match logic elsewhere treats this as an
    # automatic advance for entry1).
    for i in range(0, len(shuffled), 2):
        entry1 = shuffled[i]
        entry2 = shuffled[i + 1] if i + 1 < len(shuffled) else None

        match = Match(
            draw_id=draw.id,
            round_number=1,
            entry1_id=entry1.id,
            entry2_id=entry2.id if entry2 else None,
        )
        # A bye match has an immediate, uncontested winner.
        if entry2 is None:
            match.status = "confirmed"
            match.winner_entry_id = entry1.id
            match.result_summary = "Bye"

        db.session.add(match)

    competition.stage = "draw_review"
    db.session.commit()

    flash("Draw generated. Review the matches below, then finalize when ready.", "success")
    return redirect(url_for("admin.view_competition", competition_id=competition.id))


@admin_bp.route("/draws/<int:draw_id>/finalize", methods=["POST"])
@login_required
@admin_required
def finalize_draw(draw_id):
    """
    Locks the draw and moves the competition into "live" — from this point,
    players can see their matches and start reporting results. Per our
    plan, this is also the point at which the competition becomes visible
    to the whole club (see player/routes.py: all members can view any
    live/complete competition, not just entrants).
    """
    draw = Draw.query.get_or_404(draw_id)
    draw.is_finalized = True
    draw.competition.stage = "live"
    db.session.commit()

    flash("Draw finalized and issued. Matches are now visible to players.", "success")
    return redirect(url_for("admin.view_competition", competition_id=draw.competition_id))


# ---------------------------------------------------------------------------
# Members
# ---------------------------------------------------------------------------

@admin_bp.route("/members", methods=["GET", "POST"])
@login_required
@admin_required
def members():
    """
    Lets an admin add members directly (in addition to golfers being able
    to self-register via /register) — per our earlier decision, both paths
    are supported side by side.
    """
    from werkzeug.security import generate_password_hash

    if request.method == "POST":
        email = request.form.get("email", "").strip().lower()
        if User.query.filter_by(email=email).first():
            flash("A member with that email already exists.", "error")
        else:
            member = User(
                name=request.form["name"],
                email=email,
                phone=request.form.get("phone"),
                gender=request.form.get("gender"),
                handicap=float(request.form["handicap"]) if request.form.get("handicap") else None,
                # Admin-added members get a temporary password they should
                # change; a real deployment would email them a reset link
                # instead of a fixed default.
                password_hash=generate_password_hash("changeme123"),
                role="player",
            )
            db.session.add(member)
            db.session.commit()
            flash(f"{member.name} added. Temporary password: changeme123", "success")

    all_members = User.query.order_by(User.name).all()
    return render_template("admin/members.html", members=all_members)


# ---------------------------------------------------------------------------
# Disputes
# ---------------------------------------------------------------------------

@admin_bp.route("/disputes")
@login_required
@admin_required
def disputes():
    open_disputes = Dispute.query.filter_by(status="open").order_by(Dispute.created_at).all()
    return render_template("admin/disputes.html", disputes=open_disputes)


@admin_bp.route("/disputes/<int:dispute_id>/resolve", methods=["POST"])
@login_required
@admin_required
def resolve_dispute(dispute_id):
    """
    Admin manually decides the outcome of a disputed match. This overrides
    whatever the two conflicting player submissions said.
    """
    dispute = Dispute.query.get_or_404(dispute_id)
    winner_entry_id = request.form.get("winner_entry_id")
    result_summary = request.form.get("result_summary", "").strip()

    dispute.match.winner_entry_id = winner_entry_id
    dispute.match.result_summary = result_summary
    dispute.match.status = "confirmed"

    dispute.status = "resolved"
    dispute.admin_resolution_notes = request.form.get("notes", "")
    dispute.resolved_by_user_id = current_user.id
    dispute.resolved_at = datetime.utcnow()

    db.session.commit()
    flash("Dispute resolved and match result updated.", "success")
    return redirect(url_for("admin.disputes"))
