"""Public API endpoints (JSON responses)."""
from __future__ import annotations

import csv
import io
import json

from flask import Blueprint, request, jsonify, g, Response

from webui.data import (
    get_db,
    get_overview_stats,
    get_drafts_page,
    get_draft_detail,
    get_rating_distributions,
    get_timeline_data,
    get_ideas_by_type,
    get_category_counts,
    get_author_network_full,
    get_citation_graph,
    get_idea_clusters,
    global_search,
    get_architecture,
    get_ask_search,
)

api_bp = Blueprint("api", __name__)


def db():
    if "db" not in g:
        g.db = get_db()
    return g.db


def _to_csv_response(rows: list[dict], filename: str = "export.csv") -> Response:
    """Convert a list of dicts to a CSV download response."""
    if not rows:
        return Response("", mimetype="text/csv",
                        headers={"Content-Disposition": f"attachment; filename={filename}"})
    si = io.StringIO()
    writer = csv.DictWriter(si, fieldnames=rows[0].keys())
    writer.writeheader()
    for row in rows:
        flat = {}
        for k, v in row.items():
            if isinstance(v, (list, dict)):
                flat[k] = json.dumps(v)
            else:
                flat[k] = v
        writer.writerow(flat)
    return Response(si.getvalue(), mimetype="text/csv",
                    headers={"Content-Disposition": f"attachment; filename={filename}"})


def _results_to_csv(results: dict) -> Response:
    """Convert global search results (multi-category) to a single CSV."""
    rows = []
    for category, items in results.items():
        for item in items:
            row = {"_category": category}
            row.update(item)
            rows.append(row)
    return _to_csv_response(rows, "search_results.csv")


@api_bp.route("/api/drafts")
def api_drafts():
    page = request.args.get("page", 1, type=int)
    search = request.args.get("q", "")
    category = request.args.get("cat", "")
    source = request.args.get("source", "")
    min_score = request.args.get("min_score", 0.0, type=float)
    sort = request.args.get("sort", "score")
    sort_dir = request.args.get("dir", "desc")
    data = get_drafts_page(db(), page=page, search=search, category=category,
                           min_score=min_score, sort=sort, sort_dir=sort_dir,
                           source=source)
    if request.args.get("format") == "csv":
        return _to_csv_response(data.get("drafts", []), "drafts.csv")
    return jsonify(data)


@api_bp.route("/api/stats")
def api_stats():
    return jsonify(get_overview_stats(db()))


@api_bp.route("/api/authors/network")
def api_author_network():
    return jsonify(get_author_network_full(db()))


@api_bp.route("/api/citations")
def api_citations():
    min_refs = request.args.get("min_refs", 2, type=int)
    return jsonify(get_citation_graph(db(), min_refs=min_refs))


@api_bp.route("/api/search")
def api_search():
    q = request.args.get("q", "").strip()
    results = global_search(db(), q) if q else {"drafts": [], "ideas": [], "authors": [], "gaps": []}
    if request.args.get("format") == "csv":
        return _results_to_csv(results)
    return jsonify(results)


@api_bp.route("/api/ideas")
def api_ideas():
    data = get_ideas_by_type(db())
    if request.args.get("format") == "csv":
        return _to_csv_response(data.get("ideas", []), "ideas.csv")
    return jsonify(data)


@api_bp.route("/api/ratings")
def api_ratings():
    data = get_rating_distributions(db())
    if request.args.get("format") == "csv":
        rows = []
        for i in range(len(data.get("names", []))):
            rows.append({
                "name": data["names"][i],
                "score": data["scores"][i],
                "novelty": data["novelty"][i],
                "maturity": data["maturity"][i],
                "overlap": data["overlap"][i],
                "momentum": data["momentum"][i],
                "relevance": data["relevance"][i],
                "category": data["categories"][i],
            })
        return _to_csv_response(rows, "ratings.csv")
    return jsonify(data)


@api_bp.route("/api/timeline")
def api_timeline():
    data = get_timeline_data(db())
    return jsonify(data)


@api_bp.route("/api/idea-clusters")
def api_idea_clusters():
    data = get_idea_clusters(db())
    return jsonify(data)


@api_bp.route("/api/categories")
def api_categories():
    data = get_category_counts(db())
    if request.args.get("format") == "csv":
        rows = [{"category": k, "count": v} for k, v in data.items()]
        return _to_csv_response(rows, "categories.csv")
    return jsonify(data)


@api_bp.route("/api/drafts/<string:name>")
def api_draft_detail(name: str):
    detail = get_draft_detail(db(), name)
    if not detail:
        return jsonify({"error": "Draft not found"}), 404
    return jsonify(detail)


@api_bp.route("/api/architecture")
def api_architecture():
    return jsonify(get_architecture(db()))


@api_bp.route("/api/ask", methods=["POST"])
def api_ask():
    """Search only (free). Returns JSON with sources + cached answer if available."""
    data = request.get_json(force=True, silent=True)
    if not data or "question" not in data:
        return jsonify({"error": "Missing 'question' in request body"}), 400
    question = data["question"]
    top_k = data.get("top_k", 5)
    result = get_ask_search(db(), question, top_k=top_k)
    return jsonify(result)
