"""Tests for extraction prompt builders."""

from __future__ import annotations

from extraction.models import ExtractionField, ExtractionSchema, FieldType
from extraction.prompts import (
    build_classification_prompt,
    build_extraction_prompt,
    build_user_prompt,
)


def _sample_schema() -> ExtractionSchema:
    return ExtractionSchema(
        name="invoice",
        description="Extract invoice data",
        fields=[
            ExtractionField(
                name="vendor",
                field_type=FieldType.TEXT,
                description="Company name",
                required=True,
                examples=["Acme Corp"],
            ),
            ExtractionField(
                name="amount",
                field_type=FieldType.CURRENCY,
                required=True,
            ),
            ExtractionField(
                name="date",
                field_type=FieldType.DATE,
                required=False,
            ),
            ExtractionField(
                name="is_paid",
                field_type=FieldType.BOOLEAN,
                required=False,
            ),
            ExtractionField(
                name="line_items",
                field_type=FieldType.LIST,
                required=False,
            ),
            ExtractionField(
                name="total_units",
                field_type=FieldType.NUMBER,
                required=False,
            ),
            ExtractionField(
                name="contact",
                field_type=FieldType.ENTITY,
                required=False,
            ),
        ],
    )


class TestBuildExtractionPrompt:
    def test_contains_schema_name(self):
        prompt = build_extraction_prompt(_sample_schema())
        assert "invoice" in prompt

    def test_contains_schema_description(self):
        prompt = build_extraction_prompt(_sample_schema())
        assert "Extract invoice data" in prompt

    def test_contains_all_field_names(self):
        schema = _sample_schema()
        prompt = build_extraction_prompt(schema)
        for field in schema.fields:
            assert field.name in prompt

    def test_contains_field_description(self):
        prompt = build_extraction_prompt(_sample_schema())
        assert "Company name" in prompt

    def test_contains_examples(self):
        prompt = build_extraction_prompt(_sample_schema())
        assert "Acme Corp" in prompt

    def test_marks_required_fields(self):
        prompt = build_extraction_prompt(_sample_schema())
        assert "REQUIRED" in prompt

    def test_marks_optional_fields(self):
        prompt = build_extraction_prompt(_sample_schema())
        assert "optional" in prompt

    def test_contains_type_hints(self):
        prompt = build_extraction_prompt(_sample_schema())
        assert "plain text string" in prompt
        assert "monetary amount" in prompt.lower()
        assert "ISO 8601" in prompt

    def test_handles_all_field_types(self):
        prompt = build_extraction_prompt(_sample_schema())
        assert "boolean" in prompt.lower()
        assert "list of strings" in prompt
        assert "numeric value" in prompt
        assert "named entity" in prompt

    def test_includes_json_schema(self):
        prompt = build_extraction_prompt(_sample_schema())
        assert '"type": "object"' in prompt
        assert '"properties"' in prompt

    def test_schema_without_description(self):
        schema = ExtractionSchema(
            name="bare",
            fields=[ExtractionField(name="x", field_type=FieldType.TEXT)],
        )
        prompt = build_extraction_prompt(schema)
        assert "bare" in prompt
        # Should not crash; description line is absent


class TestBuildUserPrompt:
    def test_wraps_text(self):
        result = build_user_prompt("Hello world")
        assert "Hello world" in result
        assert "Extract structured data" in result

    def test_truncation(self):
        long_text = "a" * 200
        result = build_user_prompt(long_text, max_chars=100)
        assert "[TEXT TRUNCATED]" in result
        assert len(result) < 200 + 100  # original is truncated

    def test_no_truncation_when_under_limit(self):
        result = build_user_prompt("short text", max_chars=1000)
        assert "[TEXT TRUNCATED]" not in result

    def test_no_truncation_without_limit(self):
        long_text = "x" * 10_000
        result = build_user_prompt(long_text)
        assert long_text in result


class TestBuildClassificationPrompt:
    def test_contains_categories(self):
        prompt = build_classification_prompt(["positive", "negative", "neutral"])
        assert '"positive"' in prompt
        assert '"negative"' in prompt
        assert '"neutral"' in prompt

    def test_output_format(self):
        prompt = build_classification_prompt(["a", "b"])
        assert '"category"' in prompt
        assert '"confidence"' in prompt
