"""
CrashSense REST API — lightweight Flask server that exposes diagnosis history.

Endpoints
---------
GET  /api/v1/history                  Paginated list of all diagnoses
GET  /api/v1/history/<tx_hash>        Single diagnosis by tx hash
GET  /api/v1/history/search?q=...     Full-text search
GET  /api/v1/history/<id>/actions     AI action log for one diagnosis
GET  /api/v1/stats                    Aggregate statistics
POST /api/v1/diagnose                 Run a diagnosis via the API
GET  /api/v1/health                   Health-check / readiness

Start the server
~~~~~~~~~~~~~~~~
CLI:   ``crashsense serve --port 8787``
Code:  ``from crashsense.api import create_app; create_app().run()``
"""

from __future__ import annotations

from flask import Flask, jsonify, request

from .core.memory import MemoryStore


def create_app(db_path: str | None = None) -> Flask:
    """Factory that returns a configured Flask app."""
    app = Flask(__name__)
    store = MemoryStore(db_path=db_path)

    # ── Health ────────────────────────────────────────────────────────────

    @app.route("/api/v1/health", methods=["GET"])
    def health():
        return jsonify({"status": "ok", "service": "crashsense"})

    # ── List all diagnoses (paginated) ────────────────────────────────────

    @app.route("/api/v1/history", methods=["GET"])
    def list_history():
        page = request.args.get("page", 1, type=int)
        per_page = min(request.args.get("per_page", 50, type=int), 200)
        result = store.get_all(page=page, per_page=per_page)
        return jsonify({
            "total": result["total"],
            "page": result["page"],
            "per_page": result["per_page"],
            "pages": result["pages"],
            "items": [store.record_to_dict(r) for r in result["items"]],
        })

    # ── Get single diagnosis by tx_hash ───────────────────────────────────

    @app.route("/api/v1/history/<tx_hash>", methods=["GET"])
    def get_by_hash(tx_hash: str):
        rec = store.get_by_tx_hash(tx_hash)
        if rec is None:
            return jsonify({"error": "not_found", "message": f"No diagnosis for {tx_hash}"}), 404
        return jsonify(store.record_to_dict(rec))

    # ── Search ────────────────────────────────────────────────────────────

    @app.route("/api/v1/history/search", methods=["GET"])
    def search_history():
        q = request.args.get("q", "").strip()
        if not q:
            return jsonify({"error": "missing_query", "message": "Provide ?q=keyword"}), 400
        limit = min(request.args.get("limit", 20, type=int), 100)
        items = store.search(q, limit=limit)
        return jsonify({
            "query": q,
            "count": len(items),
            "items": [store.record_to_dict(r) for r in items],
        })

    # ── AI action log for one diagnosis ───────────────────────────────────

    @app.route("/api/v1/history/<int:diag_id>/actions", methods=["GET"])
    def get_actions(diag_id: int):
        actions = store.get_actions(diag_id)
        return jsonify({
            "diagnosis_id": diag_id,
            "count": len(actions),
            "actions": [store.action_to_dict(a) for a in actions],
        })

    # ── Aggregate stats ───────────────────────────────────────────────────

    @app.route("/api/v1/stats", methods=["GET"])
    def stats():
        return jsonify(store.get_stats())

    # ── Run a diagnosis via HTTP ──────────────────────────────────────────

    @app.route("/api/v1/diagnose", methods=["POST"])
    def api_diagnose():
        """Accept JSON ``{"tx_hash": "0x…", "chain": "ethereum", "provider": "gemini"}``."""
        body = request.get_json(silent=True) or {}
        tx_hash = body.get("tx_hash", "").strip()
        raw_text = body.get("raw_text", "").strip()

        if not tx_hash and not raw_text:
            return jsonify({"error": "bad_request", "message": "Provide tx_hash or raw_text"}), 400

        from .utils import is_valid_tx_hash, normalise_tx_hash
        from .core.tx_analyzer import TxAnalyzer
        from .core.remediation import RemediationEngine

        chain = body.get("chain", "ethereum")
        provider = body.get("provider", "gemini")

        analyzer = TxAnalyzer(provider=provider, chain=chain)

        if tx_hash:
            if not is_valid_tx_hash(tx_hash):
                return jsonify({"error": "invalid_hash", "message": "Expected 0x + 64 hex chars"}), 400
            tx_hash = normalise_tx_hash(tx_hash)
            result = analyzer.diagnose(tx_hash)
        else:
            result = analyzer.diagnose_raw(raw_text)
            tx_hash = f"raw_{MemoryStore._hash(raw_text)[:16]}"

        # Persist
        analysis = result.get("analysis", {})
        ctx = result.get("tx_context", {})
        patterns = result.get("patterns_matched", [])

        engine = RemediationEngine()
        remediation = engine.get_remediation(patterns)

        rec = store.save_diagnosis(
            tx_hash=tx_hash,
            chain=ctx.get("chain", chain),
            summary=analysis.get("explanation", ""),
            root_cause=analysis.get("root_cause", ""),
            suggested_fix=analysis.get("suggested_fix", ""),
            explanation=analysis.get("explanation", ""),
            patterns=patterns,
            remediation=remediation,
            provider=provider,
            status=ctx.get("status", ""),
            function_called=ctx.get("function_called", ""),
            from_address=ctx.get("from", ""),
            to_address=ctx.get("to", ""),
            value_eth=ctx.get("value_eth", 0.0),
            gas_used=ctx.get("gas_used", 0),
            gas_limit=ctx.get("gas_limit", 0),
            revert_reason=ctx.get("revert_reason", ""),
            tx_context=ctx,
            analysis=analysis,
            raw_input=raw_text,
        )

        # Log AI actions
        if patterns:
            store.log_action(rec.id, "pattern_match", f"Matched {len(patterns)} patterns", {"patterns": patterns})
        store.log_action(rec.id, "llm_call", f"Provider: {provider}", {"analysis": analysis})
        if remediation:
            store.log_action(rec.id, "remediation", f"{len(remediation)} fixes suggested", {"remediation": remediation})

        return jsonify(store.record_to_dict(rec)), 201

    return app


def run_server(host: str = "0.0.0.0", port: int = 8787, debug: bool = False, db_path: str | None = None):
    """Convenience function to start the API server."""
    app = create_app(db_path=db_path)
    app.run(host=host, port=port, debug=debug)
