"""BigMind Profile Web Server — Flask app served on localhost:BIGMIND_PORT (default 7700).

Started automatically as a daemon thread when the MCP server starts.
Serves a single live profile page built from the BigMind DB.
"""

import os
import threading
import logging
from datetime import datetime, timezone, timedelta

from bigmind.web_render import _render_html  # all HTML rendering lives there

logger = logging.getLogger("BigMindWeb")

_PORT = int(os.environ.get("BIGMIND_PORT", "7700"))
_AUTOOPEN = os.environ.get("BIGMIND_AUTOOPEN", "").lower() in ("1", "true", "yes")
_server_started = False


# ── Flask app ─────────────────────────────────────────────────────────────────

def _create_app():
    from flask import Flask, jsonify, request
    from bigmind import memory_store
    from bigmind.profile_builder import build_profile_data

    app = Flask(__name__)
    app.logger.setLevel(logging.WARNING)  # silence Flask request logs

    @app.route("/")
    def profile():
        user = memory_store.get_or_create_user(memory_store.get_current_username())
        data = build_profile_data(user["id"])
        return _render_html(data)

    @app.route("/api/session/<session_id>")
    def api_session(session_id):
        """Return Tier-2 summary JSON for a given session id."""
        detail = memory_store.get_session_detail(session_id)
        if not detail:
            return jsonify({"error": "No detailed summary for this session."})
        return jsonify(detail)

    @app.route("/api/search")
    def api_search():
        """Unified memory search — facts + chunks + session one-liners."""
        q = (request.args.get("q") or "").strip()
        if not q:
            return jsonify([])

        user = memory_store.get_or_create_user(memory_store.get_current_username())
        uid  = user["id"]
        results = []

        # Facts
        try:
            facts = memory_store.search_facts(uid, q, limit=5)
            for f in facts:
                results.append({
                    "type": "fact",
                    "content": f"[{f.get('category','')}] {f.get('fact','')}",
                    "date": (f.get("created_at") or "")[:10],
                    "score": 3,
                })
        except Exception:
            pass

        # Chunks
        try:
            chunks = memory_store.search_chunks(uid, q, limit=5)
            for c in chunks:
                results.append({
                    "type": "chunk",
                    "content": (c.get("content") or "")[:300],
                    "date": (c.get("created_at") or "")[:10],
                    "score": 2,
                })
        except Exception:
            pass

        # Session one-liners (simple LIKE — no FTS needed)
        try:
            from bigmind.db import db as _db
            with _db() as conn:
                rows = conn.execute(
                    """SELECT id, one_liner, started_at FROM sessions
                       WHERE user_id=? AND ended_at IS NOT NULL
                         AND one_liner LIKE ?
                       ORDER BY started_at DESC LIMIT 5""",
                    (uid, f"%{q}%"),
                ).fetchall()
            for r in rows:
                results.append({
                    "type": "session",
                    "content": r["one_liner"],
                    "date": (r.get("started_at") or "")[:10],
                    "score": 1,
                })
        except Exception:
            pass

        # Sort by type score desc, deduplicate by content
        seen = set()
        final = []
        for r in sorted(results, key=lambda x: -x["score"]):
            key = r["content"][:80]
            if key not in seen:
                seen.add(key)
                final.append(r)

        return jsonify(final[:15])

    return app


# ── Daemon thread startup ─────────────────────────────────────────────────────

def _port_in_use(port: int) -> bool:
    """Return True if something is already listening on 127.0.0.1:<port>."""
    import socket
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.settimeout(0.2)
        return s.connect_ex(("127.0.0.1", port)) == 0


def start_web_server() -> str:
    """Start the Flask profile server in a background daemon thread.

    Safe to call multiple times (only starts once).  If another BigMind
    instance is already serving the port this process skips Flask startup
    gracefully — the MCP tools still work, the profile page is served by
    the other instance (same DB, same data).

    The fix for the multi-IDE port-conflict bug: we check the port *before*
    setting _server_started = True.  Previously the flag was set immediately
    after t.start(), so a failed Flask bind (Address already in use) left
    _server_started = True with no Flask running — permanent lock-out.
    """
    global _server_started
    if _server_started:
        return f"http://localhost:{_PORT}"

    if _port_in_use(_PORT):
        # Another BigMind process already owns the port — skip Flask startup.
        # Don't set _server_started = True so if that process dies and this
        # one is restarted, it can try again cleanly.
        logger.info(
            "BigMind profile server already running at http://localhost:%d "
            "(another IDE instance). Skipping Flask startup.", _PORT
        )
        return f"http://localhost:{_PORT}"

    app = _create_app()
    _started_event = threading.Event()
    _bind_failed   = []   # non-empty if Flask couldn't bind

    def _run():
        import logging as _log
        _log.getLogger("werkzeug").setLevel(_log.ERROR)
        try:
            _started_event.set()   # signal that the thread is running
            app.run(host="127.0.0.1", port=_PORT, debug=False, use_reloader=False)
        except OSError as exc:
            _bind_failed.append(str(exc))
            logger.warning("BigMind web server failed to bind port %d: %s", _PORT, exc)

    t = threading.Thread(target=_run, daemon=True, name="BigMindWebServer")
    t.start()
    _started_event.wait(timeout=2.0)   # wait for thread to actually start

    # Only mark as started if Flask didn't immediately report a bind error
    if not _bind_failed:
        _server_started = True
        logger.info("BigMind profile server started at http://localhost:%d", _PORT)
        if _AUTOOPEN:
            import webbrowser, time
            time.sleep(1.0)
            webbrowser.open(f"http://localhost:{_PORT}")
    else:
        logger.warning(
            "BigMind web server could not start (port %d in use). "
            "Profile page unavailable from this IDE instance.", _PORT
        )

    return f"http://localhost:{_PORT}"


def get_profile_url() -> str:
    return f"http://localhost:{_PORT}"
