"""
Unit tests for server/resource_engine.py.

Run with: cd server && ../venv/bin/python3 -m unittest tests.test_resource_engine -v
"""
import os
import sys
import tempfile
import unittest

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))


class ResourceEngineTests(unittest.TestCase):
    def setUp(self):
        self._tmpdir = tempfile.mkdtemp()
        os.environ["CA_DATA_DIR"] = self._tmpdir
        for mod in ("db", "resource_engine"):
            sys.modules.pop(mod, None)
        import db as db_mod
        import resource_engine as re_mod
        global db, re
        db, re = db_mod, re_mod
        db.init_db()
        self.senior = db.create_user(1, "Senior One", "senior1@test.com", "testpass123", "staff")
        self.senior_position_id = db.query(
            "SELECT id FROM job_position WHERE firm_id = 1 AND name = 'Senior'", one=True)["id"]
        db.execute("INSERT INTO employee_profile (user_id, job_position_id, weekly_capacity_hours) VALUES (?,?,?)",
                  (self.senior, self.senior_position_id, 40))
        self.client_id = db.execute("INSERT INTO client (firm_id, code, name) VALUES (1, 'CL-01', 'Test Client')")

    def test_workload_report_reflects_allocated_hours_against_capacity(self):
        eng_id = db.execute("INSERT INTO engagement (client_id, type, status) VALUES (?, 'tax', 'planning')",
                            (self.client_id,))
        db.execute("INSERT INTO engagement_member (engagement_id, user_id, allocated_hours) VALUES (?,?,?)",
                  (eng_id, self.senior, 20))
        report = re.workload_report(1)
        row = next(r for r in report if r["user_id"] == self.senior)
        self.assertEqual(row["allocated_hours"], 20)
        self.assertEqual(row["weekly_capacity_hours"], 40)
        self.assertEqual(row["utilization_pct"], 50.0)

    def test_workload_report_excludes_closed_engagements(self):
        eng_id = db.execute("INSERT INTO engagement (client_id, type, status) VALUES (?, 'tax', 'closed')",
                            (self.client_id,))
        db.execute("INSERT INTO engagement_member (engagement_id, user_id, allocated_hours) VALUES (?,?,?)",
                  (eng_id, self.senior, 20))
        report = re.workload_report(1)
        row = next(r for r in report if r["user_id"] == self.senior)
        self.assertEqual(row["allocated_hours"], 0)

    def test_workload_report_only_includes_active_employees(self):
        db.execute("UPDATE app_user SET is_active = 0 WHERE id = ?", (self.senior,))
        report = re.workload_report(1)
        self.assertFalse(any(r["user_id"] == self.senior for r in report))

    def test_suggest_ranks_skill_and_position_match_above_a_plain_available_candidate(self):
        generalist = db.create_user(1, "Generalist", "generalist@test.com", "testpass123", "staff")
        skill_id = db.execute("INSERT INTO skill (firm_id, name) VALUES (1, 'NFRS')")
        db.execute("INSERT INTO employee_skill (user_id, skill_id, proficiency) VALUES (?,?,5)",
                  (self.senior, skill_id))
        results = re.suggest_candidates(1, job_position_id=self.senior_position_id, skill_id=skill_id)
        ranked_ids = [r["user_id"] for r in results]
        self.assertLess(ranked_ids.index(self.senior), ranked_ids.index(generalist))
        top = next(r for r in results if r["user_id"] == self.senior)
        self.assertTrue(top["matches_requested_skill"])
        self.assertTrue(top["matches_requested_position"])

    def test_suggest_prefers_less_utilized_candidate_when_skills_are_equal(self):
        other = db.create_user(1, "Other Senior", "other_senior@test.com", "testpass123", "staff")
        db.execute("INSERT INTO employee_profile (user_id, job_position_id, weekly_capacity_hours) VALUES (?,?,?)",
                  (other, self.senior_position_id, 40))
        eng_id = db.execute("INSERT INTO engagement (client_id, type, status) VALUES (?, 'tax', 'planning')",
                            (self.client_id,))
        db.execute("INSERT INTO engagement_member (engagement_id, user_id, allocated_hours) VALUES (?,?,?)",
                  (eng_id, self.senior, 35))  # nearly fully booked
        results = re.suggest_candidates(1, job_position_id=self.senior_position_id)
        ranked_ids = [r["user_id"] for r in results]
        self.assertLess(ranked_ids.index(other), ranked_ids.index(self.senior))

    def test_suggest_respects_limit(self):
        for i in range(15):
            db.create_user(1, f"Extra {i}", f"extra{i}@test.com", "testpass123", "staff")
        results = re.suggest_candidates(1, limit=5)
        self.assertEqual(len(results), 5)

    def test_no_filters_still_returns_every_active_employee_ranked_by_availability(self):
        results = re.suggest_candidates(1)
        self.assertGreaterEqual(len(results), 1)
        for r in results:
            self.assertIsNone(r["matches_requested_skill"])
            self.assertIsNone(r["matches_requested_position"])


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