"""Routes: admin scanner"""
from datetime import datetime
from flask import jsonify, render_template, request, session

from nexora.config import ADMIN_USERNAME
from nexora.core import app
from nexora.database.connection import execute, query
from nexora.utils.formatting import pretty_dt
from nexora.services.ticket_codes import normalize_qr_token
from nexora.services.registrations import registration_details
from nexora.services.qualifier_entries import (
    _qualifier_entry_decision,
    _verify_qualifier_entry,
    find_qualifier_entry_by_code,
)
from nexora.services.tickets import (
    atomic_checkin,
    atomic_reject,
    find_ticket_by_code,
    group_checkin_summary,
    log_ticket_action,
    ticket_payload,
)
from nexora.security.permissions import (
    admin_required,
    forbidden_response,
    has_permission,
    permission_required,
)


@app.route("/admin/qr-scanner")
@admin_required
@permission_required("scan_qr_codes", "manually_verify_tickets", any_of=True)
def admin_qr_scanner():
    return render_template("admin_qr_scanner.html")


@app.route("/admin/qr-scanner/verify", methods=["POST"])
@admin_required
@permission_required("scan_qr_codes", "manually_verify_tickets", any_of=True)
def verify_qr_ticket():
    """Scan lookup only. It never changes the record â€” the admin decides
    Approve / Reject from the overlay that opens after the scan."""
    payload = request.get_json(silent=True) or {}
    raw_code = (payload.get("token") or "").strip()
    code = normalize_qr_token(raw_code)
    if not code:
        return jsonify({"ok": False, "status": "invalid", "message": "No QR code or ticket number received."}), 400

    if raw_code.upper().startswith("NQ:"):
        qrecord = find_qualifier_entry_by_code(code)
        if qrecord:
            return _verify_qualifier_entry(qrecord)

    qrecord = find_qualifier_entry_by_code(code)
    if qrecord:
        return _verify_qualifier_entry(qrecord)

    ticket_record = find_ticket_by_code(code)
    if not ticket_record:
        return jsonify(
            {"ok": False, "status": "invalid", "message": "No ticket matched this QR code or ticket number."}
        ), 404

    row = ticket_record["registration"]
    ticket = ticket_record["ticket"]
    entry_status = (ticket["entry_status"] or "pending").lower()
    payment_status = (row["payment_status"] or "unpaid").lower()

    if entry_status == "approved":
        status, message = "already", "ALREADY CHECKED IN - Double Entry Detected"
    elif entry_status == "rejected":
        reason_text = ticket.get("rejection_reason") or ticket.get("entry_note") or "No reason provided"
        rejected_at = pretty_dt(ticket.get("rejected_at") or ticket.get("entry_marked_at")) if ticket.get("rejected_at") or ticket.get("entry_marked_at") else ""
        status, message = "rejected", f"ENTRY REJECTED â€” {reason_text}" + (f" ({rejected_at})" if rejected_at else "")
    elif payment_status in ("unpaid", "under_verification"):
        status, message = "payment_required", "PAYMENT NOT VERIFIED"
    elif payment_status == "paid" and entry_status != "approved":
        status, message = "paid_ready", "PAID â€” ENTRY READY"
    else:
        status, message = "found", "Ticket Found â€” Decide Entry"

    data = ticket_payload(ticket_record, status, message)
    data["token"] = ticket["ticket_token"] or code
    data["payment_status_raw"] = payment_status
    data["entry_status_raw"] = entry_status

    if not has_permission("view_scanned_record"):
        data["name"] = data.get("name", "")[:1] + "***"
        data["player_name"] = data["name"]
        data["email"] = "***"
        data["phone"] = "***"
        data["cnic"] = "***"
        data["institution"] = "***"
        data["team_members"] = []
        data["group_leader"] = "***"
        data["proof_url"] = ""
        data["rejection_reason"] = ""
        data["checked_in_by"] = ""
        data["checkin_gate"] = ""

    return jsonify(data)


@app.route("/admin/qr-scanner/confirm-payment", methods=["POST"])
@admin_required
@permission_required("confirm_payments")
def qr_confirm_payment():
    """Confirm payment from within the scanner overlay (same-screen flow).
    After confirming, the overlay refreshes to show the ticket as Paid/Entry Ready."""
    payload = request.get_json(silent=True) or {}
    code = normalize_qr_token(payload.get("token"))
    if not code:
        return jsonify({"ok": False, "message": "No ticket reference received."}), 400

    ticket_record = find_ticket_by_code(code)
    if not ticket_record:
        return jsonify({"ok": False, "message": "Ticket not found."}), 404

    row = ticket_record["registration"]
    payment_status = (row["payment_status"] or "unpaid").lower()
    entry_status = (row["entry_status"] or "pending").lower()

    if entry_status == "approved":
        return jsonify({"ok": False, "status": "already", "message": "Ticket already checked in. Cannot change payment status."}), 409

    if payment_status == "paid":
        return jsonify({"ok": False, "status": "paid_ready", "message": "Payment is already confirmed."}), 409

    now = datetime.now().isoformat(timespec="seconds")
    details = registration_details(row["id"])
    payable_amount = details["total_payable"] if details else "Rs. 0"

    execute(
        "UPDATE registrations SET payment_status = 'paid', amount_paid = ?, verified_at = COALESCE(verified_at, ?) WHERE id = ?",
        (payable_amount, now, row["id"]),
    )

    # Re-fetch and return updated ticket data
    fresh = find_ticket_by_code(ticket_record["ticket"]["ticket_token"])
    if fresh:
        data = ticket_payload(fresh, "paid_ready", "PAID â€” ENTRY READY")
        data["token"] = ticket_record["ticket"]["ticket_token"] or code
        data["payment_status_raw"] = "paid"
        data["entry_status_raw"] = "pending"
    else:
        data = {"ok": True, "status": "paid_ready", "message": "Payment confirmed. Ticket refreshed.", "token": code}

    log_ticket_action(ticket_record, "payment_confirmed", payment_status, "paid", "", "")
    return jsonify(data)


@app.route("/admin/qr-scanner/decision", methods=["POST"])
@admin_required
def qr_entry_decision():
    """Admin presses Approve (entry allowed) or Reject (entry denied)."""
    payload = request.get_json(silent=True) or {}
    code = normalize_qr_token(payload.get("token"))
    decision = (payload.get("decision") or "").strip().lower()
    reason = (payload.get("reason") or "").strip()
    gate = (payload.get("gate") or "").strip()
    override = bool(payload.get("override"))
    override_reason = (payload.get("override_reason") or "").strip()

    if decision not in {"approved", "rejected", "approved_team"}:
        return jsonify({"ok": False, "status": "invalid", "message": "Unknown decision."}), 400
    if decision in {"approved", "approved_team"} and not has_permission("approve_entry"):
        return forbidden_response()
    if decision == "rejected" and not has_permission("reject_entry"):
        return forbidden_response()
    if override and not has_permission("override_duplicate_entry"):
        return forbidden_response()
    if not code:
        return jsonify({"ok": False, "status": "invalid", "message": "No ticket reference received."}), 400

    raw_code = (payload.get("token") or "").strip()
    if raw_code.upper().startswith("NQ:"):
        qrecord = find_qualifier_entry_by_code(code)
        if not qrecord:
            return jsonify({"ok": False, "status": "invalid", "message": "This qualifier ticket no longer exists."}), 404
        return _qualifier_entry_decision(qrecord, decision, reason, gate, override, override_reason)

    qrecord = find_qualifier_entry_by_code(code)
    if qrecord:
        return _qualifier_entry_decision(qrecord, decision, reason, gate, override, override_reason)

    ticket_record = find_ticket_by_code(code)
    if not ticket_record:
        return jsonify({"ok": False, "status": "invalid", "message": "This ticket no longer exists."}), 404

    row = ticket_record["registration"]
    ticket = ticket_record["ticket"]
    table = "member_tickets" if ticket_record["kind"] == "member" else "registrations"
    ticket_id = ticket["id"]
    previous_status = (ticket["entry_status"] or "pending").lower()
    payment_status = (row["payment_status"] or "unpaid").lower()
    marked_at = datetime.now().isoformat(timespec="seconds")

    # SAFETY: Block approval of unpaid/under-verification tickets
    if decision in ("approved", "approved_team") and payment_status in ("unpaid", "under_verification") and not override:
        return jsonify({
            "ok": False, "status": "payment_required",
            "message": "Cannot approve entry: payment is " + payment_status.replace("_", " ").title() + ". Confirm payment first."
        }), 403
    if decision == "approved_team":
        if (row["entry_type"] or "").lower() != "group":
            return jsonify({"ok": False, "status": "invalid", "message": "Entire-team check-in is only available for group registrations."}), 400
        if group_checkin_summary(row)["checked_in"] and not override:
            return jsonify(ticket_payload(ticket_record, "already", "Some team members are already checked in. Use each member ticket individually, or provide an admin override.")), 409
        if override and not override_reason:
            return jsonify({"ok": False, "status": "invalid", "message": "An admin override reason is required."}), 400
        staff = session.get("admin_username", ADMIN_USERNAME)
        targets = [("registrations", row["id"], row["ticket_serial"])]
        targets.extend(("member_tickets", item["id"], item["ticket_serial"]) for item in query(
            "SELECT id, ticket_serial FROM member_tickets WHERE registration_id = ?", (row["id"],)
        ))
        all_checked = True
        for target_table, target_id, target_serial in targets:
            ok = atomic_checkin(target_table, target_id, staff, gate or "Main Gate", override, override_reason)
            execute(
                """INSERT INTO ticket_audit_log
                   (registration_id, ticket_serial, action, previous_status, new_status, reason, gate_location, staff_username, created_at)
                   VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""",
                (row["id"], target_serial, "team_override_approved" if override else "team_approved",
                 previous_status, "approved" if ok else previous_status, override_reason, gate or "Main Gate", staff, marked_at),
            )
            if not ok:
                all_checked = False
        if not all_checked:
            return jsonify(ticket_payload(ticket_record, "already", "Some team members are already checked in.")), 409
        execute("UPDATE registrations SET payment_status = 'paid', verified_at = COALESCE(verified_at, ?) WHERE id = ?", (marked_at, row["id"]))
        fresh = find_ticket_by_code(ticket["ticket_token"])
        data = ticket_payload(fresh, "approved", "Entire Team Checked In")
        data["token"] = ticket["ticket_token"] or code
        return jsonify(data)
    if decision == "approved":
        if previous_status == "approved" and not override:
            return jsonify(ticket_payload(ticket_record, "already", "This ticket has already been used.")), 409
        if previous_status == "approved" and override and not override_reason:
            return jsonify({"ok": False, "status": "invalid", "message": "An admin override reason is required."}), 400
        staff = session.get("admin_username", ADMIN_USERNAME)
        ok = atomic_checkin(table, ticket_id, staff, gate or "Main Gate", override, override_reason)
        if not ok:
            return jsonify(ticket_payload(ticket_record, "already", "This ticket has already been used.")), 409
        execute("UPDATE registrations SET payment_status = 'paid', verified_at = COALESCE(verified_at, ?) WHERE id = ?", (marked_at, row["id"]))
        log_ticket_action(ticket_record, "override_approved" if override else "approved", previous_status, "approved", override_reason, gate or "Main Gate")
        message = "Entry Approved" if not override else "Entry Approved by Admin Override"
    else:
        if not reason:
            return jsonify({"ok": False, "status": "invalid", "message": "Select a rejection reason before rejecting this ticket."}), 400
        staff = session.get("admin_username", ADMIN_USERNAME)
        ok = atomic_reject(table, ticket_id, staff, reason, gate)
        if not ok:
            return jsonify(ticket_payload(ticket_record, "already", "This ticket has already been used.")), 409
        log_ticket_action(ticket_record, "rejected", previous_status, "rejected", reason, gate)
        message = "Entry Rejected"

    fresh = find_ticket_by_code(ticket["ticket_token"])
    data = ticket_payload(fresh, decision, message)
    data["token"] = ticket["ticket_token"] or code
    return jsonify(data)
