import tempfile
import unittest
from pathlib import Path
import uuid

from hiveos import db as db_module
from hiveos.config import USER_CAPABILITIES_HEADER
from hiveos.db import init_db
from hiveos.intelligence import tracing as tracing_module
from hiveos.session_manager import session_manager
from web_interface import app


class IntentRuntimeApiTests(unittest.TestCase):
    def setUp(self):
        self._original_trace_db_async = tracing_module.TRACE_DB_ASYNC
        self._original_trace_sampling_enabled = tracing_module.TRACE_SAMPLING_ENABLED
        self._original_trace_log_path = tracing_module.TRACE_LOG_PATH

        self._db_path = Path(tempfile.gettempdir()) / f"hive-test-{uuid.uuid4().hex}.db"
        db_module.DB_PATH = str(self._db_path)
        init_db()

        self._trace_log_path = str(Path(tempfile.gettempdir()) / f"hive-trace-{uuid.uuid4().hex}.log")
        tracing_module.TRACE_LOG_PATH = self._trace_log_path
        tracing_module.TRACE_DB_ASYNC = False
        tracing_module.TRACE_SAMPLING_ENABLED = False

        self._cleanup_sessions()
        self.client = app.test_client()

    def tearDown(self):
        self._cleanup_sessions()
        tracing_module.TRACE_DB_ASYNC = self._original_trace_db_async
        tracing_module.TRACE_SAMPLING_ENABLED = self._original_trace_sampling_enabled
        tracing_module.TRACE_LOG_PATH = self._original_trace_log_path
        try:
            if self._db_path.exists():
                self._db_path.unlink()
        except Exception:
            pass
        self._cleanup_trace_files()

    def _cleanup_sessions(self):
        for session_id in list(session_manager.sessions.keys()):
            try:
                session_manager.delete_session(session_id)
            except Exception:
                pass

    def _cleanup_trace_files(self):
        base = Path(self._trace_log_path)
        for path in [base] + list(base.parent.glob(f"{base.name}.*")):
            try:
                if path.exists():
                    path.unlink()
            except Exception:
                pass

    def _headers(self, user_id, session_id=None):
        headers = {
            "X-User-ID": user_id,
            USER_CAPABILITIES_HEADER: "admin",
        }
        if session_id:
            headers["X-Session-ID"] = session_id
        return headers

    def _create_session(self, user_id):
        response = self.client.post(
            "/create_session",
            json={"label": "intent-test", "user_id": user_id},
            headers=self._headers(user_id),
        )
        self.assertEqual(200, response.status_code)
        return response.get_json()["session_id"]

    def test_intent_preview_and_apply_terminal_plan(self):
        user_id = "intent-user"
        session_id = self._create_session(user_id)

        preview = self.client.post(
            "/intent_preview",
            json={
                "prompt": 'spin up a terminal and echo "hello friend. Welcome to HiveOS"',
                "scope": "session",
                "approval_mode": "auto",
                "use_model": False,
            },
            headers=self._headers(user_id, session_id),
        )
        self.assertEqual(200, preview.status_code)
        payload = preview.get_json()
        run_spec = payload["run_spec"]
        self.assertEqual("session", run_spec["scope"])
        self.assertGreaterEqual(len(run_spec["steps"]), 2)
        self.assertEqual("terminal.session", run_spec["steps"][0]["tool_id"])

        apply_resp = self.client.post(
            "/intent_apply",
            json={"run_spec_id": run_spec["run_spec_id"]},
            headers=self._headers(user_id, session_id),
        )
        self.assertEqual(200, apply_resp.status_code)
        outcome = apply_resp.get_json()["outcome"]
        self.assertIn(outcome["status"], {"completed", "partially_applied"})
        self.assertGreaterEqual(outcome["applied_steps"], 1)
        self.assertTrue(outcome.get("task_id"))
        self.assertTrue(outcome.get("agent_id"))
        self.assertEqual("runtime_task", outcome.get("execution_path"))

        status_resp = self.client.get("/status", headers=self._headers(user_id, session_id))
        self.assertEqual(200, status_resp.status_code)
        tasks = status_resp.get_json().get("tasks", [])
        self.assertTrue(any(task.get("task_id") == outcome["task_id"] for task in tasks))

        ai_events = tracing_module.read_trace_events(limit=500, filters={"event_type": "ai_output"})
        self.assertTrue(ai_events)
        last_ai = ai_events[-1]
        model_meta = last_ai.get("model") or {}
        self.assertTrue(str(model_meta.get("provider") or "").strip())
        self.assertTrue(str(model_meta.get("name") or "").strip())


if __name__ == "__main__":
    unittest.main()
