import json
from pathlib import Path

import pytest
from collections_extended import RangeMap
from pymultirole_plugins.v1.schema import Document, DocumentList, Sentence

from pysegmenters_blingfire.blingfire import BlingFireParameters, BlingFireSegmenter


def test_blingfire_en():
    TEXT = """CLAIRSSON INTERNATIONAL REPORTS LOSS

Clairson International Corp. said it expects to report a net loss for its
second quarter ended March 26. The company doesn't expect to meet analysts' profit
estimates of $3.9 to $4 million, or 76 cents a share to 79 cents a share, for its
year ending Sept. 24, according to Pres. John Doe."""
    model = BlingFireSegmenter.get_model()
    model_class = model.model_construct().__class__
    assert model_class == BlingFireParameters
    segmenter = BlingFireSegmenter()
    parameters = BlingFireParameters()
    docs: list[Document] = segmenter.segment([Document(text=TEXT)], parameters)
    doc0 = docs[0]
    assert len(doc0.sentences) == 2
    sents = [doc0.text[s.start : s.end] for s in doc0.sentences]
    assert (
        sents[0]
        == """CLAIRSSON INTERNATIONAL REPORTS LOSS

Clairson International Corp. said it expects to report a net loss for its
second quarter ended March 26."""
    )
    assert (
        sents[1]
        == """The company doesn't expect to meet analysts' profit
estimates of $3.9 to $4 million, or 76 cents a share to 79 cents a share, for its
year ending Sept. 24, according to Pres. John Doe."""
    )


def test_blingfire_emoticon():
    testdir = Path(__file__).parent
    source = Path(testdir, "data/emojis.json")
    with source.open("r") as fin:
        jdocs = json.load(fin)
    original_docs = [Document(**jdoc) for jdoc in jdocs]
    segmenter = BlingFireSegmenter()
    parameters = BlingFireParameters()
    docs: list[Document] = segmenter.segment(original_docs, parameters)
    assert len(docs) == 1
    doc0 = docs[0]
    assert len(doc0.sentences) == 2
    for sent in doc0.sentences:
        ctext = doc0.text[sent.start : sent.end]
        print("===========================================================")
        print(ctext)

    dl = DocumentList(root=docs)
    result = Path(testdir, "data/emojis_segmented.json")
    with result.open("w") as fout:
        print(dl.model_dump_json(exclude_none=True, exclude_unset=True, indent=2), file=fout)


def test_blingfire_single_sentence():
    """A single sentence should produce exactly one span covering the full text."""
    TEXT = "This is a single sentence."
    segmenter = BlingFireSegmenter()
    parameters = BlingFireParameters()
    docs = segmenter.segment([Document(text=TEXT)], parameters)
    doc = docs[0]
    assert len(doc.sentences) == 1
    assert doc.text[doc.sentences[0].start : doc.sentences[0].end] == TEXT


def test_blingfire_three_sentences():
    """Three clearly delimited sentences should each be detected."""
    TEXT = "The cat sat on the mat. The dog ran in the park. The bird flew in the sky."
    segmenter = BlingFireSegmenter()
    parameters = BlingFireParameters()
    docs = segmenter.segment([Document(text=TEXT)], parameters)
    doc = docs[0]
    assert len(doc.sentences) == 3
    sents = [doc.text[s.start : s.end] for s in doc.sentences]
    assert sents[0] == "The cat sat on the mat."
    assert sents[1] == "The dog ran in the park."
    assert sents[2] == "The bird flew in the sky."


def test_blingfire_multiple_documents():
    """Segmenting a batch should process each document independently."""
    TEXT1 = "First document. It has two sentences."
    TEXT2 = "Second document. It also has two sentences."
    segmenter = BlingFireSegmenter()
    parameters = BlingFireParameters()
    docs = segmenter.segment([Document(text=TEXT1), Document(text=TEXT2)], parameters)
    assert len(docs) == 2
    assert len(docs[0].sentences) == 2
    assert len(docs[1].sentences) == 2


def test_blingfire_offsets_valid():
    """All sentence offsets must be within text bounds, ordered, and non-overlapping."""
    TEXT = "First sentence. Second sentence. Third sentence."
    segmenter = BlingFireSegmenter()
    parameters = BlingFireParameters()
    docs = segmenter.segment([Document(text=TEXT)], parameters)
    doc = docs[0]
    prev_end = 0
    for sent in doc.sentences:
        assert sent.start >= 0
        assert sent.end <= len(doc.text)
        assert sent.start < sent.end
        assert sent.start >= prev_end
        prev_end = sent.end


def test_blingfire_replaces_existing_sentences():
    """Pre-existing sentences on a document must be cleared before segmenting."""
    TEXT = "Hello world. Goodbye world."
    doc = Document(text=TEXT, sentences=[Sentence(start=0, end=5)])
    segmenter = BlingFireSegmenter()
    parameters = BlingFireParameters()
    docs = segmenter.segment([doc], parameters)
    assert len(docs[0].sentences) == 2


def test_blingfire_empty_text():
    """An empty text should yield no sentences."""
    segmenter = BlingFireSegmenter()
    parameters = BlingFireParameters()
    docs = segmenter.segment([Document(text="")], parameters)
    assert docs[0].sentences == []


def test_blingfire_modifies_in_place():
    """segment() must return the same document objects, modified in place."""
    TEXT = "One sentence."
    doc = Document(text=TEXT)
    segmenter = BlingFireSegmenter()
    parameters = BlingFireParameters()
    result = segmenter.segment([doc], parameters)
    assert result[0] is doc


@pytest.mark.skip(reason="Not a test")
def test_summarizer_mazars():
    testdir = Path(__file__).parent / "data"
    json_file = testdir / "leasecontractsextraction-documents.json"
    with json_file.open("r") as fin:
        docs = json.load(fin)
    docs = [Document(**doc) for doc in docs]
    parameters = BlingFireParameters()
    segmenter = BlingFireSegmenter()

    docs = segmenter.segment(docs, parameters)
    segs = RangeMap()
    for doc in docs:
        for _i, seg in enumerate(doc.sentences):
            segs[seg.start : seg.end] = seg
        for a in doc.annotations:
            seg_start = segs[a.start]
            seg_end = segs[a.end - 1]
            if seg_start != seg_end:
                pass
    seg_file = testdir / "leasecontractsextraction-documents-reseg.json"
    dl = DocumentList(root=docs)
    with seg_file.open("w") as fout:
        print(dl.model_dump_json(exclude_none=True, exclude_unset=True, indent=2), file=fout)
