"""Simulation CRUD + workflow endpoints."""
from __future__ import annotations

from datetime import UTC, datetime

from flask import Blueprint, g, jsonify, request

from backend.app.auth import login_required, role_required
from backend.app.extensions import db
from backend.app.models import Engagement
from backend.app.models.simulation import Simulation, SimulationStatus
from backend.app.serializers import serialize_simulation
from backend.app.services import simulation_workflow

simulations_bp = Blueprint("simulations", __name__)


# ---------------------------------------------------------------------------
# Nested under /api/engagements/<eid>/simulations
# ---------------------------------------------------------------------------


@simulations_bp.get("/api/engagements/<int:eid>/simulations")
@login_required
def list_simulations(eid: int):
    engagement = db.session.get(Engagement, eid)
    if engagement is None:
        return jsonify({"error": "Engagement not found"}), 404
    sims = (
        Simulation.query.filter_by(engagement_id=eid)
        .order_by(Simulation.created_at.desc())
        .all()
    )
    return jsonify([serialize_simulation(s) for s in sims]), 200


@simulations_bp.post("/api/engagements/<int:eid>/simulations")
@role_required("admin", "redteam")
def create_simulation(eid: int):
    engagement = db.session.get(Engagement, eid)
    if engagement is None:
        return jsonify({"error": "Engagement not found"}), 404

    data = request.get_json(silent=True) or {}
    name = (data.get("name") or "").strip()
    if not name:
        return jsonify({"error": "name is required"}), 400

    sim = Simulation(
        engagement_id=eid,
        name=name,
        status=SimulationStatus.PENDING,
        created_at=datetime.now(UTC),
        created_by_id=g.current_user.id,
    )
    db.session.add(sim)
    db.session.commit()
    return jsonify(serialize_simulation(sim)), 201


# ---------------------------------------------------------------------------
# Flat /api/simulations/<sid>
# ---------------------------------------------------------------------------


@simulations_bp.get("/api/simulations/<int:sid>")
@login_required
def get_simulation(sid: int):
    sim = db.session.get(Simulation, sid)
    if sim is None:
        return jsonify({"error": "Simulation not found"}), 404
    return jsonify(serialize_simulation(sim)), 200


@simulations_bp.patch("/api/simulations/<int:sid>")
@login_required
def update_simulation(sid: int):
    sim = db.session.get(Simulation, sid)
    if sim is None:
        return jsonify({"error": "Simulation not found"}), 404

    user = g.current_user
    data = request.get_json(silent=True) or {}
    if not data:
        return jsonify(serialize_simulation(sim)), 200

    err = simulation_workflow.apply_patch(sim, data, user)
    if err is not None:
        return err

    db.session.commit()
    return jsonify(serialize_simulation(sim)), 200


@simulations_bp.delete("/api/simulations/<int:sid>")
@role_required("admin", "redteam")
def delete_simulation(sid: int):
    sim = db.session.get(Simulation, sid)
    if sim is None:
        return jsonify({"error": "Simulation not found"}), 404
    db.session.delete(sim)
    db.session.commit()
    return "", 204


@simulations_bp.post("/api/simulations/<int:sid>/transition")
@login_required
def transition_simulation(sid: int):
    sim = db.session.get(Simulation, sid)
    if sim is None:
        return jsonify({"error": "Simulation not found"}), 404

    data = request.get_json(silent=True) or {}
    to_status = data.get("to", "")

    err = simulation_workflow.transition(sim, to_status, g.current_user)
    if err is not None:
        return err

    return jsonify(serialize_simulation(sim)), 200


# ---------------------------------------------------------------------------
# MITRE autocomplete
# ---------------------------------------------------------------------------


@simulations_bp.get("/api/mitre/techniques")
@login_required
def mitre_techniques():
    from backend.app.services import mitre as mitre_svc

    if not mitre_svc.mitre_loaded:
        return jsonify({"error": "mitre bundle not loaded"}), 503

    q = request.args.get("q", "").strip()
    results = mitre_svc.search(q)
    return jsonify(results), 200
