"""Tests for rbsp.runtime.api -- one-line API functions."""

import os
import sys
import unittest

sys.path.insert(0, os.path.dirname(__file__))
from conftest import RBSPTestCase, FIXED_TIMESTAMP, SAMPLE_TEXTS

from rbsp.runtime.engine import RBSPEngine, IndexStats, Result
from rbsp.runtime import api


class TestApiInit(RBSPTestCase):
    """Tests for api.init()."""

    def setUp(self):
        super().setUp()
        RBSPEngine.reset()

    def tearDown(self):
        RBSPEngine.reset()
        super().tearDown()

    def test_init_creates_rbsp_dir(self):
        api.init(self.tmp_dir)
        rbsp_dir = os.path.join(self.tmp_dir, ".rbsp")
        self.assertTrue(os.path.isdir(rbsp_dir))

    def test_init_creates_index_subdir(self):
        api.init(self.tmp_dir)
        index_dir = os.path.join(self.tmp_dir, ".rbsp", "index")
        self.assertTrue(os.path.isdir(index_dir))

    def test_init_creates_plugins_subdir(self):
        api.init(self.tmp_dir)
        plugins_dir = os.path.join(self.tmp_dir, ".rbsp", "plugins")
        self.assertTrue(os.path.isdir(plugins_dir))

    def test_init_sets_engine_initialized(self):
        api.init(self.tmp_dir)
        engine = RBSPEngine.get_instance()
        self.assertTrue(engine.is_initialized)

    def test_init_with_overrides(self):
        api.init(self.tmp_dir, overrides={"max_results": 5})
        engine = RBSPEngine.get_instance()
        self.assertEqual(engine.config.max_results, 5)


class TestApiIndex(RBSPTestCase):
    """Tests for api.index()."""

    def setUp(self):
        super().setUp()
        RBSPEngine.reset()
        # Create some files to index
        src_dir = os.path.join(self.tmp_dir, "src")
        os.makedirs(src_dir, exist_ok=True)
        self.make_sample_file(os.path.join("src", "app.py"), "def main():\n    pass\n")
        self.make_sample_file(os.path.join("src", "util.py"), "def helper():\n    return 42\n")

    def tearDown(self):
        RBSPEngine.reset()
        super().tearDown()

    def test_index_returns_index_stats(self):
        stats = api.index(self.tmp_dir)
        self.assertIsInstance(stats, IndexStats)

    def test_index_finds_files(self):
        stats = api.index(self.tmp_dir)
        self.assertGreaterEqual(stats.files_indexed, 1)

    def test_index_initializes_engine_if_needed(self):
        stats = api.index(self.tmp_dir)
        engine = RBSPEngine.get_instance()
        self.assertTrue(engine.is_initialized)

    def test_index_force_flag(self):
        api.index(self.tmp_dir)
        stats = api.index(self.tmp_dir, force=True)
        self.assertGreaterEqual(stats.files_indexed, 1)


class TestApiResolve(RBSPTestCase):
    """Tests for api.resolve()."""

    def setUp(self):
        super().setUp()
        RBSPEngine.reset()
        src_dir = os.path.join(self.tmp_dir, "src")
        os.makedirs(src_dir, exist_ok=True)
        self.make_sample_file(
            os.path.join("src", "login.py"),
            "def login(username, password):\n    return authenticate(username, password)\n",
        )
        self.make_sample_file(
            os.path.join("src", "data.py"),
            "def process_data(items):\n    return [transform(i) for i in items]\n",
        )
        # Pre-init and index
        api.init(self.tmp_dir)
        engine = RBSPEngine.get_instance()
        engine.index(self.tmp_dir)

    def tearDown(self):
        RBSPEngine.reset()
        super().tearDown()

    def test_resolve_returns_list(self):
        results = api.resolve("login", scope=self.tmp_dir)
        self.assertIsInstance(results, list)

    def test_resolve_returns_result_objects(self):
        results = api.resolve("login", scope=self.tmp_dir)
        for r in results:
            self.assertIsInstance(r, Result)

    def test_resolve_finds_relevant(self):
        results = api.resolve("login username password", scope=self.tmp_dir)
        if results:
            paths = [r.path for r in results]
            login_found = any("login" in p for p in paths)
            self.assertTrue(login_found)


class TestApiSearch(RBSPTestCase):
    """Tests for api.search()."""

    def setUp(self):
        super().setUp()
        RBSPEngine.reset()
        src_dir = os.path.join(self.tmp_dir, "src")
        os.makedirs(src_dir, exist_ok=True)
        self.make_sample_file(
            os.path.join("src", "calc.py"),
            "def calculate(x, y):\n    return x + y\n",
        )
        api.init(self.tmp_dir)
        engine = RBSPEngine.get_instance()
        engine.index(self.tmp_dir)

    def tearDown(self):
        RBSPEngine.reset()
        super().tearDown()

    def test_search_returns_list(self):
        results = api.search("calculate", scope=self.tmp_dir)
        self.assertIsInstance(results, list)

    def test_search_delegates_to_engine(self):
        results = api.search("calculate", scope=self.tmp_dir)
        for r in results:
            self.assertIsInstance(r, Result)


class TestApiStatus(RBSPTestCase):
    """Tests for api.status()."""

    def setUp(self):
        super().setUp()
        RBSPEngine.reset()

    def tearDown(self):
        RBSPEngine.reset()
        super().tearDown()

    def test_status_returns_dict(self):
        result = api.status(self.tmp_dir)
        self.assertIsInstance(result, dict)

    def test_status_has_expected_keys(self):
        result = api.status(self.tmp_dir)
        for key in ("initialized", "platform", "index_entries", "watching"):
            self.assertIn(key, result)

    def test_status_initialized_after_call(self):
        result = api.status(self.tmp_dir)
        self.assertTrue(result["initialized"])


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