
from flask import (Blueprint, render_template, request,
                   session, jsonify, Response, abort)
from ..decorators import client_required
from ..db import (get_client_categories, log_action,
                  search_entity, resolve_entity_id, ENTITY_PARAM_MAP)
from ..ssrs import get_report_params, stream_report
from ..db_dashboard import (
    get_dashboard_data,
    get_dashboard_insights,
    stream_dashboard_insights,
    invalidate_client_cache,
)
from flask import stream_with_context

client_bp = Blueprint("client", __name__, url_prefix="/client")
ALLOWED_FORMATS = {"PDF", "EXCELOPENXML", "CSV", "WORD"}
PARAM_TO_ENTITY = {k: v[0] for k, v in ENTITY_PARAM_MAP.items()}


def _check_path(report_path: str) -> bool:
    folder = session.get("ssrs_folder", "")
    if not folder:
        return False
    return (report_path.startswith(f"/{folder}/")
            or report_path.startswith(f"/{folder}"))


# ── DASHBOARD PAGE ────────────────────────────────────────────────────────────

@client_bp.route("/dashboard")
@client_required
def dashboard():
    categories = get_client_categories(session["user_id"])
    folder = session.get("ssrs_folder", "")
    return render_template(
        "client/dashboard.html",
        client_name=session["user_name"],
        folder=folder,
        categories=categories,
        category_list=list(categories.keys()),
        param_entity_map=PARAM_TO_ENTITY,
    )


# ── PHASE 1: Chart data  (~300ms first load, ~0ms cached) ────────────────────
#
# Uses in-memory cache (TTL: 10 min, per client_db).
# Pass ?refresh=1 to force-bypass cache (triggered by the Refresh button).

@client_bp.route("/api/dashboard-data")
@client_required
def api_dashboard_data():
    client_db = session.get("client_db") or None
    if not client_db:
        return jsonify({"error": "No client database configured for this account."}), 400

    force = request.args.get("refresh", "0") == "1"

    try:
        data = get_dashboard_data(client_db, force=force)
        return jsonify(data)
    except Exception as e:
        import traceback; traceback.print_exc()
        return jsonify({"error": str(e)}), 500


# ── PHASE 2a: LLM insights — JSON (cached, ~0ms if warm) ─────────────────────
#
# Kept for backward compatibility. Prefer the SSE endpoint below for
# better UX (insights appear one-by-one as they arrive).

@client_bp.route("/api/dashboard-insights")
@client_required
def api_dashboard_insights():
    client_db = session.get("client_db") or None
    if not client_db:
        return jsonify({"error": "No client database configured for this account."}), 400

    force = request.args.get("refresh", "0") == "1"

    try:
        chart_data = get_dashboard_data(client_db)
        insights   = get_dashboard_insights(chart_data, client_db=client_db, force=force)
        return jsonify({"insights": insights})
    except Exception as e:
        import traceback; traceback.print_exc()
        return jsonify({"error": str(e)}), 500


# ── PHASE 2b: LLM insights — SSE streaming ───────────────────────────────────
#
# Each insight is sent as soon as the LLM responds.
# On cache hit: all insights stream instantly (no LLM cost).
# On cache miss: insights appear one-by-one (~1-2s each) while charts
#               are already visible from Phase 1.
#
# Event format:  data: {"key": "monthly", "text": "...", "cached": true/false}
# Terminal event: data: {"done": true}

@client_bp.route("/api/dashboard-insights-stream")
@client_required
def api_dashboard_insights_stream():
    client_db = session.get("client_db") or None
    if not client_db:
        # SSE error event
        import json
        def err():
            yield f'data: {json.dumps({"error": "No client DB"})}\n\n'
        return Response(err(), mimetype="text/event-stream")

    force = request.args.get("refresh", "0") == "1"

    # Fetch chart data (fast — likely cached from Phase 1 call)
    try:
        chart_data = get_dashboard_data(client_db)
    except Exception as e:
        import traceback, json; traceback.print_exc()
        def err():
            yield f'data: {json.dumps({"error": str(e)})}\n\n'
        return Response(err(), mimetype="text/event-stream")

    return Response(
        stream_with_context(
            stream_dashboard_insights(chart_data, client_db=client_db, force=force)
        ),
        mimetype="text/event-stream",
        headers={
            "Cache-Control":   "no-cache",
            "X-Accel-Buffering": "no",    # disable nginx buffering
        },
    )


# ── REPORTS PAGE ──────────────────────────────────────────────────────────────

@client_bp.route("/reports")
@client_required
def reports():
    categories = get_client_categories(session["user_id"])
    folder = session.get("ssrs_folder", "")
    return render_template(
        "client/reports.html",
        client_name=session["user_name"],
        folder=folder,
        categories=categories,
        category_list=list(categories.keys()),
        active_cat=request.args.get("cat", ""),
        param_entity_map=PARAM_TO_ENTITY,
    )


@client_bp.route("/api/params")
@client_required
def api_params():
    report_id   = request.args.get("id", "")
    report_path = request.args.get("path", "")
    if not _check_path(report_path):
        return jsonify([])
    params = get_report_params(report_id) if report_id else []
    for p in params:
        entity = PARAM_TO_ENTITY.get(p["name"].lower())
        if entity:
            p["entityLookup"] = entity
    return jsonify(params)


@client_bp.route("/api/search")
@client_required
def api_search():
    entity_type = request.args.get("type", "").strip()
    query       = request.args.get("q",    "").strip()
    if not entity_type or not query:
        return jsonify([])
    client_db = session.get("client_db") or None
    return jsonify(search_entity(entity_type, query, db_name=client_db))


@client_bp.route("/download")
@client_required
def download():
    report_path = request.args.get("path",   "")
    report_name = request.args.get("name",   "Report")
    fmt         = request.args.get("format", "EXCELOPENXML").upper()

    if not _check_path(report_path):
        return abort(403)
    if fmt not in ALLOWED_FORMATS:
        fmt = "EXCELOPENXML"

    skip = {"path", "name", "format"}
    raw_params = {k: v for k, v in request.args.items()
                  if k not in skip and v.strip()}

    client_db = session.get("client_db") or None
    resolved  = {}
    for param_name, param_value in raw_params.items():
        entity = PARAM_TO_ENTITY.get(param_name.lower())
        if entity:
            real_id = resolve_entity_id(entity, param_value, db_name=client_db)
            resolved[param_name] = real_id if real_id else param_value
        else:
            resolved[param_name] = param_value

    resp, ext, content_type = stream_report(report_path, fmt, resolved)
    if resp is None:
        return "Report generation failed.", 500

    log_action(session["user_id"], f"DOWNLOAD_{fmt}",
               report_name=report_name, ip=request.remote_addr,
               extra=str(resolved) if resolved else "")

    return Response(
        resp.iter_content(chunk_size=8192),
        status=resp.status_code,
        content_type=content_type,
        headers={"Content-Disposition": f'attachment; filename="{report_name}.{ext}"'}
    )
