# Feature: trading-feedback-engine, Property 1: Chunking round-trip and size constraint
"""Property-based tests for report data chunking.

Feature: trading-feedback-engine

Tests the chunking round-trip and size constraint property from the design
specification: for any input string, splitting it into chunks with a maximum
size limit produces chunks where (a) every chunk is ≤ the size limit in
characters (for chunks that don't contain a single oversized line), (b) no
chunk is empty (except when the input itself is empty, which produces exactly
one empty chunk), and (c) concatenating all chunks in order reconstructs the
original input string.
"""
from __future__ import annotations

from hypothesis import given, settings
from hypothesis import strategies as st

from services.reporting.summarizer import chunk_data

# ---------------------------------------------------------------------------
# Property 1: Chunking Round-Trip and Size Constraint
# Validates: Requirements 2.2
# ---------------------------------------------------------------------------


@given(
    text=st.text(),
    max_chars=st.integers(min_value=1, max_value=10000),
)
@settings(max_examples=100)
def test_chunk_data_round_trip(text: str, max_chars: int) -> None:
    """**Validates: Requirements 2.2**

    For any input string and any max_chars ≥ 1, concatenating all chunks
    produced by chunk_data SHALL reconstruct the original input string
    exactly (round-trip property).
    """
    chunks = chunk_data(text, max_chars)
    reconstructed = "".join(chunks)
    assert reconstructed == text, (
        f"Round-trip failed: concatenation of {len(chunks)} chunks does not "
        f"equal original input.\n"
        f"  original length: {len(text)}\n"
        f"  reconstructed length: {len(reconstructed)}\n"
        f"  max_chars: {max_chars}"
    )


@given(
    text=st.text(),
    max_chars=st.integers(min_value=1, max_value=10000),
)
@settings(max_examples=100)
def test_chunk_data_no_empty_chunks(text: str, max_chars: int) -> None:
    """**Validates: Requirements 2.2**

    For any input string and any max_chars ≥ 1, chunk_data SHALL produce
    no empty chunks — except when the input itself is empty, in which case
    it SHALL produce exactly one empty chunk.
    """
    chunks = chunk_data(text, max_chars)

    if text == "":
        assert chunks == [""], (
            f"Empty input should produce exactly [''], got {chunks!r}"
        )
    else:
        for i, chunk in enumerate(chunks):
            assert chunk != "", (
                f"Chunk {i} is empty for non-empty input.\n"
                f"  input length: {len(text)}\n"
                f"  max_chars: {max_chars}\n"
                f"  total chunks: {len(chunks)}"
            )


@given(
    text=st.text(),
    max_chars=st.integers(min_value=1, max_value=10000),
)
@settings(max_examples=100)
def test_chunk_data_size_constraint(text: str, max_chars: int) -> None:
    """**Validates: Requirements 2.2**

    For any input string and any max_chars ≥ 1, every chunk produced by
    chunk_data SHALL be ≤ max_chars in length — UNLESS the chunk contains
    a single line that by itself exceeds max_chars (since chunk_data never
    breaks mid-line, such a line is emitted as its own chunk).

    A chunk is considered "oversized due to a single long line" when it
    consists of exactly one segment (a line with its trailing newline, or
    the final line without one) whose length exceeds max_chars.
    """
    chunks = chunk_data(text, max_chars)

    for i, chunk in enumerate(chunks):
        if len(chunk) > max_chars:
            # This chunk exceeds the limit. It must be because it contains
            # a single line that is itself longer than max_chars.
            # A single-segment chunk has at most one newline (at the end).
            lines_in_chunk = chunk.split("\n")
            # If the chunk ends with \n, split produces a trailing empty string
            non_empty_lines = [ln for ln in lines_in_chunk if ln]
            assert len(non_empty_lines) <= 1, (
                f"Chunk {i} exceeds max_chars={max_chars} "
                f"(len={len(chunk)}) but contains multiple non-empty lines, "
                f"which should not happen.\n"
                f"  lines: {non_empty_lines!r}"
            )
