#!/usr/bin/env python3
"""
Tests for training data quality filter.
"""

import json
import os
import sys
import tempfile
import unittest

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from quality_filter import score_specificity, score_length_ratio, score_code_correctness, score_pair, filter_pairs


class TestSpecificity(unittest.TestCase):

    def test_generic_response_scores_low(self):
        text = "I don't know. It depends on many factors. There are many ways to approach this."
        score = score_specificity(text)
        self.assertLess(score, 0.4)

    def test_specific_response_scores_high(self):
        text = 'Run: curl -s https://api.example.com/v1/repos | python3 -c "import sys,json; print(json.load(sys.stdin))"'
        score = score_specificity(text)
        self.assertGreater(score, 0.6)

    def test_code_block_boosts_score(self):
        text = """Here's the fix:
```python
def hello():
    return "world"
```"""
        score = score_specificity(text)
        self.assertGreater(score, 0.5)

    def test_long_detailed_response(self):
        text = " ".join(["word"] * 150) + " GET /api/v1/repos"
        score = score_specificity(text)
        self.assertGreater(score, 0.5)

    def test_short_response_penalized(self):
        score = score_specificity("yes")
        self.assertLess(score, 0.4)


class TestLengthRatio(unittest.TestCase):

    def test_balanced_ratio(self):
        score = score_length_ratio("short prompt", "This is a medium length response with some detail.")
        self.assertEqual(score, 1.0)

    def test_too_short_response(self):
        score = score_length_ratio("A long prompt with many words here", "ok")
        self.assertLess(score, 1.0)

    def test_empty_returns_zero(self):
        self.assertEqual(score_length_ratio("", "something"), 0.0)
        self.assertEqual(score_length_ratio("something", ""), 0.0)


class TestCodeCorrectness(unittest.TestCase):

    def test_no_code_returns_one(self):
        self.assertEqual(score_code_correctness("Just text, no code."), 1.0)

    def test_valid_python(self):
        text = '```python\ndef foo():\n    return 42\n```'
        self.assertEqual(score_code_correctness(text), 1.0)

    def test_valid_json(self):
        text = '```json\n{"key": "value"}\n```'
        self.assertEqual(score_code_correctness(text), 1.0)

    def test_invalid_python(self):
        text = '```python\ndef foo(\n    return broken\n```'
        score = score_code_correctness(text)
        self.assertLess(score, 1.0)


class TestScorePair(unittest.TestCase):

    def test_good_pair(self):
        pair = {
            "prompt": "How do I list files in Python?",
            "response": 'Use `os.listdir()` or `pathlib.Path.iterdir()`. Example:\n```python\nfrom pathlib import Path\nfor f in Path(".").iterdir():\n    print(f)\n```'
        }
        scores = score_pair(pair)
        self.assertGreater(scores["composite"], 0.4)

    def test_bad_pair(self):
        pair = {
            "prompt": "How do I deploy?",
            "response": "It depends. There are many ways. I don't know your setup."
        }
        scores = score_pair(pair)
        self.assertLess(scores["composite"], 0.4)

    def test_empty_pair_returns_zero(self):
        scores = score_pair({})
        self.assertEqual(scores["composite"], 0.0)


class TestFilterPairs(unittest.TestCase):

    def test_filter_removes_low_quality(self):
        pairs = [
            json.dumps({"prompt": "How?", "response": "Yes."}),
            json.dumps({"prompt": "List files?", "response": 'Use os.listdir():\n```python\nimport os\nos.listdir(".")\n```'}),
            json.dumps({"prompt": "Deploy?", "response": "It depends. I don't know."}),
        ]

        with tempfile.NamedTemporaryFile(mode="w", suffix=".jsonl", delete=False) as f:
            f.write("\n".join(pairs) + "\n")
            input_path = f.name

        with tempfile.NamedTemporaryFile(mode="w", suffix=".jsonl", delete=False) as f:
            output_path = f.name

        try:
            result = filter_pairs(input_path, output_path, threshold=0.3)
            self.assertEqual(result["total"], 3)
            self.assertGreater(result["kept"], 0)
            self.assertGreater(result["removed"], 0)

            # Verify output is valid JSONL
            with open(output_path) as f:
                for line in f:
                    json.loads(line.strip())
        finally:
            os.unlink(input_path)
            os.unlink(output_path)


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