"""MeasurementTec blueprint - recipe selection and measurement execution."""
from flask import (
    Blueprint, flash, jsonify, redirect, render_template,
    request, session, url_for,
)
from flask_babel import gettext as _

from blueprints.auth import login_required, role_required
from config import Config
from services.api_client import api_client
from services.file_proxy import proxy_file

measure_bp = Blueprint("measure", __name__)


# ---------------------------------------------------------------------------
# Route: Recipe selection
# ---------------------------------------------------------------------------
@measure_bp.route("/select")
@login_required
@role_required("MeasurementTec")
def select_recipe():
    """Recipe selection page with search and barcode support."""
    # Fail-fast if STATION_CODE is not configured
    if not Config.STATION_CODE:
        return render_template("errors/station_not_configured.html"), 503

    # Load recipes filtered by station
    try:
        resp = api_client.get_station_recipes(Config.STATION_CODE)
    except Exception as e:
        return render_template(
            "errors/station_not_configured.html", error=str(e),
        ), 502

    if isinstance(resp, dict) and resp.get("error"):
        flash(
            _("Errore nel caricamento delle ricette: %(detail)s",
              detail=resp.get("detail", "")),
            "error",
        )
        recipes = []
    else:
        # API may return paginated envelope or plain list
        recipes = resp.get("items", resp) if isinstance(resp, dict) else resp

    # Auto-fill from query params
    auto_recipe_code = request.args.get("recipe", "")
    auto_lot = request.args.get("lot", session.get("lot_number", ""))
    auto_serial = request.args.get("serial", session.get("serial_number", ""))

    return render_template(
        "measure/select_recipe.html",
        recipes=recipes,
        station_code=Config.STATION_CODE,
        auto_recipe_code=auto_recipe_code,
        auto_lot=auto_lot,
        auto_serial=auto_serial,
    )


# ---------------------------------------------------------------------------
# Route: Task list for a recipe
# ---------------------------------------------------------------------------
@measure_bp.route("/tasks/<int:recipe_id>")
@login_required
@role_required("MeasurementTec")
def task_list(recipe_id: int):
    """Task list for selected recipe."""
    # Persist lot/serial from query params into session
    lot_number = request.args.get(
        "lot_number", session.get("lot_number", ""),
    )
    serial_number = request.args.get(
        "serial_number", session.get("serial_number", ""),
    )
    if lot_number:
        session["lot_number"] = lot_number
    if serial_number:
        session["serial_number"] = serial_number

    # Load recipe details
    recipe_resp = api_client.get(f"/api/recipes/{recipe_id}")
    if recipe_resp.get("error"):
        flash(
            _("Ricetta non trovata: %(detail)s",
              detail=recipe_resp.get("detail", "")),
            "error",
        )
        return redirect(url_for("measure.select_recipe"))

    # Load tasks for this recipe
    tasks_resp = api_client.get(f"/api/recipes/{recipe_id}/tasks")
    if isinstance(tasks_resp, dict) and tasks_resp.get("error"):
        flash(
            _("Errore nel caricamento dei task: %(detail)s",
              detail=tasks_resp.get("detail", "")),
            "error",
        )
        tasks = []
    else:
        tasks = tasks_resp if isinstance(tasks_resp, list) else tasks_resp.get("items", [])

    return render_template(
        "measure/task_list.html",
        recipe=recipe_resp,
        tasks=tasks,
        lot_number=lot_number,
        serial_number=serial_number,
    )


# ---------------------------------------------------------------------------
# Route: Task execution (measurement input)
# ---------------------------------------------------------------------------
@measure_bp.route("/execute/<int:task_id>")
@login_required
@role_required("MeasurementTec")
def task_execute(task_id: int):
    """Execute measurements for a task."""
    # Load task + subtasks
    task_resp = api_client.get(f"/api/tasks/{task_id}")
    if task_resp.get("error"):
        flash(
            _("Task non trovato: %(detail)s",
              detail=task_resp.get("detail", "")),
            "error",
        )
        return redirect(url_for("measure.select_recipe"))

    lot_number = session.get("lot_number", "")
    serial_number = session.get("serial_number", "")

    # Load all task IDs for this recipe (ordered) for auto-advance
    recipe_id = task_resp.get("recipe_id")
    all_task_ids = []
    measurement_interval_minutes = None
    if recipe_id:
        tasks_resp = api_client.get(f"/api/recipes/{recipe_id}/tasks")
        if isinstance(tasks_resp, list):
            sorted_tasks = sorted(tasks_resp, key=lambda t: t.get("order_index", 0))
            all_task_ids = [t["id"] for t in sorted_tasks]
        recipe_resp = api_client.get(f"/api/recipes/{recipe_id}")
        if not recipe_resp.get("error"):
            measurement_interval_minutes = recipe_resp.get("measurement_interval_minutes")

    return render_template(
        "measure/task_execute.html",
        task=task_resp,
        lot_number=lot_number,
        serial_number=serial_number,
        all_task_ids=all_task_ids,
        measurement_interval_minutes=measurement_interval_minutes,
    )


# ---------------------------------------------------------------------------
# Route: Task completion summary
# ---------------------------------------------------------------------------
@measure_bp.route("/complete/<int:recipe_id>")
@login_required
@role_required("MeasurementTec")
def task_complete(recipe_id: int):
    """Task completion summary with all measurements."""
    # Retrieve version_id from query params
    version_id = request.args.get("version_id")

    # Load recipe for context
    recipe_resp = api_client.get(f"/api/recipes/{recipe_id}")
    if recipe_resp.get("error"):
        flash(
            _("Ricetta non trovata: %(detail)s",
              detail=recipe_resp.get("detail", "")),
            "error",
        )
        return redirect(url_for("measure.select_recipe"))

    # Load tasks+subtasks for this recipe to build subtask and task lookup
    tasks_resp = api_client.get(f"/api/recipes/{recipe_id}/tasks")
    subtask_map = {}
    subtask_task_map = {}  # subtask_id → task info
    if isinstance(tasks_resp, list):
        for task in tasks_resp:
            for st in task.get("subtasks", []):
                subtask_map[st["id"]] = st
                subtask_task_map[st["id"]] = {
                    "id": task["id"],
                    "title": task.get("title", ""),
                    "order_index": task.get("order_index", 0),
                }

    # Load measurements if version_id provided
    measurements = []
    if version_id:
        meas_resp = api_client.get(
            "/api/measurements",
            params={"version_id": version_id, "per_page": 500},
        )
        if not (isinstance(meas_resp, dict) and meas_resp.get("error")):
            raw = (
                meas_resp if isinstance(meas_resp, list)
                else meas_resp.get("items", [])
            )
            # Enrich each measurement with nested subtask data
            for m in raw:
                st = subtask_map.get(m.get("subtask_id"), {})
                m["subtask"] = st
                m["task_info"] = subtask_task_map.get(m.get("subtask_id"), {})
                # Compute deviation if not present
                if m.get("deviation") is None and st.get("nominal") is not None:
                    try:
                        m["deviation"] = m["value"] - st["nominal"]
                    except (TypeError, KeyError):
                        m["deviation"] = 0.0
            measurements = raw

    lot_number = session.get("lot_number", "")
    serial_number = session.get("serial_number", "")

    return render_template(
        "measure/task_complete.html",
        recipe=recipe_resp,
        measurements=measurements,
        lot_number=lot_number,
        serial_number=serial_number,
    )


# ---------------------------------------------------------------------------
# Route: Barcode lookup (AJAX)
# ---------------------------------------------------------------------------
@measure_bp.route("/lookup-barcode", methods=["POST"])
@login_required
@role_required("MeasurementTec")
def lookup_barcode():
    """Look up a recipe by barcode/code. Returns JSON for AJAX calls."""
    data = request.get_json(silent=True) or {}
    code = data.get("code", "").strip()

    if not code:
        return jsonify({"error": True, "detail": _("Codice non fornito")}), 400

    resp = api_client.get(f"/api/recipes/code/{code}")
    if resp.get("error"):
        return jsonify({
            "error": True,
            "detail": resp.get("detail", _("Ricetta non trovata")),
        }), 404

    return jsonify(resp)


# ---------------------------------------------------------------------------
# Route: Save lot/serial to session (AJAX)
# ---------------------------------------------------------------------------
@measure_bp.route("/save-traceability", methods=["POST"])
@login_required
@role_required("MeasurementTec")
def save_traceability():
    """Save lot_number and serial_number to session."""
    data = request.get_json(silent=True) or {}
    lot = data.get("lot_number", "").strip()
    serial = data.get("serial_number", "").strip()

    if lot:
        session["lot_number"] = lot
    if serial:
        session["serial_number"] = serial

    return jsonify({"ok": True})


# ---------------------------------------------------------------------------
# Route: Save measurement (AJAX proxy to FastAPI)
# ---------------------------------------------------------------------------
@measure_bp.route("/save-measurement", methods=["POST"])
@login_required
@role_required("MeasurementTec")
def save_measurement():
    """Save a single measurement value via API proxy.

    Expects JSON body:
        subtask_id: int
        task_id: int
        value: float
        pass_fail: str  ('pass' | 'warning' | 'fail')
        deviation: float
        lot_number: str (optional)
        serial_number: str (optional)

    Returns JSON with the created measurement or error.
    """
    data = request.get_json(silent=True) or {}

    # Validate required fields
    subtask_id = data.get("subtask_id")
    version_id = data.get("version_id")
    value = data.get("value")

    if subtask_id is None or version_id is None or value is None:
        return jsonify({
            "error": True,
            "detail": _("Dati mancanti: subtask_id, version_id e value sono obbligatori"),
        }), 400

    # Build payload for the FastAPI backend
    payload = {
        "subtask_id": subtask_id,
        "version_id": version_id,
        "value": value,
        "lot_number": data.get("lot_number", session.get("lot_number", "")),
        "serial_number": data.get("serial_number", session.get("serial_number", "")),
        "input_method": data.get("input_method", "manual"),
    }

    resp = api_client.post("/api/measurements", data=payload)

    if resp.get("error"):
        status_code = resp.get("status_code", 500)
        return jsonify({
            "error": True,
            "detail": resp.get("detail", _("Errore nel salvataggio")),
        }), status_code if status_code >= 400 else 500

    return jsonify(resp), 201


# ---------------------------------------------------------------------------
# Route: Validate supervisor credentials (AJAX)
# ---------------------------------------------------------------------------
@measure_bp.route("/validate-supervisor", methods=["POST"])
@login_required
@role_required("MeasurementTec")
def validate_supervisor():
    """Validate supervisor (capoturno) credentials for out-of-tolerance authorization."""
    data = request.get_json(silent=True) or {}
    username = data.get("username", "").strip()
    password = data.get("password", "")

    if not username or not password:
        return jsonify({"error": True, "detail": _("Username e password richiesti")}), 400

    resp = api_client.post("/api/auth/login", data={"username": username, "password": password})

    if resp.get("error"):
        return jsonify({"error": True, "detail": _("Credenziali non valide")}), 401

    user = resp.get("user", {})
    is_supervisor = "Supervisor" in (user.get("roles") or [])
    if not (is_supervisor or user.get("is_admin")):
        return jsonify({"error": True, "detail": _("Utente non autorizzato (richiesto capoturno)")}), 403

    return jsonify({"authorized": True, "supervisor": user.get("display_name", username)}), 200


# ---------------------------------------------------------------------------
# Route: File proxy (browser can't send X-API-Key directly)
# ---------------------------------------------------------------------------
@measure_bp.route("/api/files/<path:file_path>", methods=["GET"])
@login_required
def api_get_file(file_path: str):
    """Proxy: Serve file from API server (browser can't send X-API-Key)."""
    return proxy_file(file_path)
