import json
from pathlib import Path

from pymultirole_plugins.v1.schema import Annotation, Document, DocumentList

from pyprocessors_capitalizer.capitalizer import CapitalizerParameters, CapitalizerProcessor


def _make_doc(text: str, annotations: list[Annotation]) -> Document:
    return Document(text=text, annotations=annotations)


def test_capitalizer():
    annotator = CapitalizerProcessor()
    parameters = CapitalizerParameters()
    testdir = Path(__file__).parent / "data"
    json_file = testdir / "x_cago_ner_de-document-test2.json"
    with json_file.open("r") as fin:
        doc = json.load(fin)
    original_text = doc["text"]
    docs = [Document(**doc)]
    docs = annotator.process(docs, parameters)
    new_text = docs[0].text
    assert len(new_text) == len(original_text)
    assert len(new_text) == len(docs[0].altTexts[0].text)
    json_file = testdir / "x_cago_ner_de-document-new2.json"
    dl = DocumentList(root=docs)
    with json_file.open("w") as fout:
        print(dl.model_dump_json(exclude_none=True, exclude_unset=True, indent=2), file=fout)


def test_capitalizer_no_annotations():
    """Documents with no annotations are returned unchanged."""
    annotator = CapitalizerProcessor()
    parameters = CapitalizerParameters()
    doc = Document(text="hello world")
    docs = annotator.process([doc], parameters)
    assert docs[0].text == "hello world"
    assert docs[0].altTexts is None


def test_capitalizer_basic():
    """Annotated spans are capitalized word by word."""
    annotator = CapitalizerProcessor()
    parameters = CapitalizerParameters()
    text = "the quick brown fox"
    doc = _make_doc(text, [Annotation(start=4, end=19, labelName="NE")])
    docs = annotator.process([doc], parameters)
    # "quick brown fox" → "Quick Brown Fox", prefix "the " unchanged
    assert docs[0].text == "the Quick Brown Fox"


def test_capitalizer_exceptions():
    """Words in the exception list are not capitalized."""
    annotator = CapitalizerProcessor()
    parameters = CapitalizerParameters(exceptions="de,la")
    text = "brasserie de la paix"
    doc = _make_doc(text, [Annotation(start=0, end=20, labelName="ORG")])
    docs = annotator.process([doc], parameters)
    assert docs[0].text == "Brasserie de la Paix"


def test_capitalizer_empty_exceptions():
    """Empty exception list means all words are capitalized."""
    annotator = CapitalizerProcessor()
    parameters = CapitalizerParameters(exceptions="")
    text = "the quick brown fox"
    doc = _make_doc(text, [Annotation(start=0, end=19, labelName="NE")])
    docs = annotator.process([doc], parameters)
    assert docs[0].text == "The Quick Brown Fox"


def test_capitalizer_sentence_annotations_skipped():
    """Annotations with labelName 'sentence' are excluded from capitalization."""
    annotator = CapitalizerProcessor()
    parameters = CapitalizerParameters()
    text = "hello world"
    doc = _make_doc(
        text,
        [
            Annotation(start=0, end=5, labelName="NE"),
            Annotation(start=0, end=11, labelName="sentence"),
        ],
    )
    docs = annotator.process([doc], parameters)
    # only "hello" span should be capitalized, not the full sentence span
    assert docs[0].text == "Hello world"


def test_capitalizer_annotation_with_explicit_text():
    """When annotation.text is set, it is used instead of the document slice."""
    annotator = CapitalizerProcessor()
    parameters = CapitalizerParameters()
    text = "see john doe here"
    # annotation covers "john doe" but has an explicit .text override
    doc = _make_doc(
        text,
        [Annotation(start=4, end=12, labelName="PER", text="john doe")],
    )
    docs = annotator.process([doc], parameters)
    assert docs[0].text == "see John Doe here"


def test_capitalizer_original_text_stored():
    """Original text is stored as an altText entry with the configured name."""
    annotator = CapitalizerProcessor()
    parameters = CapitalizerParameters()
    text = "hello world"
    doc = _make_doc(text, [Annotation(start=0, end=5, labelName="NE")])
    docs = annotator.process([doc], parameters)
    assert docs[0].altTexts is not None
    alt = docs[0].altTexts[0]
    assert alt.name == "_original_text"
    assert alt.text == text


def test_capitalizer_custom_alttext_name():
    """Custom original_altText name is used for storing the original text."""
    annotator = CapitalizerProcessor()
    parameters = CapitalizerParameters(original_altText="__backup__")
    text = "hello world"
    doc = _make_doc(text, [Annotation(start=0, end=5, labelName="NE")])
    docs = annotator.process([doc], parameters)
    assert docs[0].altTexts[0].name == "__backup__"


def test_capitalizer_annotations_cleared():
    """Annotations are cleared after processing."""
    annotator = CapitalizerProcessor()
    parameters = CapitalizerParameters()
    text = "hello world"
    doc = _make_doc(text, [Annotation(start=0, end=5, labelName="NE")])
    docs = annotator.process([doc], parameters)
    assert docs[0].annotations is None


def test_capitalizer_multiple_documents():
    """All documents in the list are processed."""
    annotator = CapitalizerProcessor()
    parameters = CapitalizerParameters()
    docs = [
        _make_doc("hello world", [Annotation(start=0, end=5, labelName="NE")]),
        _make_doc("foo bar", [Annotation(start=0, end=7, labelName="NE")]),
    ]
    docs = annotator.process(docs, parameters)
    assert docs[0].text == "Hello world"
    assert docs[1].text == "Foo Bar"


def test_capitalizer_get_model():
    """get_model returns CapitalizerParameters."""
    assert CapitalizerProcessor.get_model() is CapitalizerParameters
