"""Tests for Annotation entity."""

from __future__ import annotations

from uuid import uuid4

import pytest

from noteflow.domain.entities.annotation import Annotation
from noteflow.domain.value_objects import AnnotationId, AnnotationType, MeetingId

# Test constants
TWO_HOURS_SECONDS = 7200.0


class TestAnnotation:
    """Tests for Annotation entity."""

    def test_annotation_valid(self) -> None:
        """Annotation can be created with valid fields."""
        annotation = Annotation(
            id=AnnotationId(uuid4()),
            meeting_id=MeetingId(uuid4()),
            annotation_type=AnnotationType.NOTE,
            text="Important point",
            start_time=1.0,
            end_time=2.0,
        )

        assert annotation.text == "Important point", "text should match provided value"
        assert annotation.duration == 1.0, "duration should be end - start"
        assert annotation.has_segments() is False, "no segment_ids means has_segments is False"

    def test_annotation_invalid_times_raises(self) -> None:
        """Annotation raises when end_time < start_time."""
        with pytest.raises(ValueError, match=r"end_time .* must be >= start_time"):
            Annotation(
                id=AnnotationId(uuid4()),
                meeting_id=MeetingId(uuid4()),
                annotation_type=AnnotationType.DECISION,
                text="Bad timing",
                start_time=5.0,
                end_time=2.0,
            )

    def test_annotation_has_segments(self) -> None:
        """has_segments reflects segment_ids list."""
        annotation = Annotation(
            id=AnnotationId(uuid4()),
            meeting_id=MeetingId(uuid4()),
            annotation_type=AnnotationType.ACTION_ITEM,
            text="Follow up",
            start_time=0.0,
            end_time=1.0,
            segment_ids=[1, 2],
        )

        assert annotation.has_segments() is True, "has_segments should be True when segment_ids provided"
        assert annotation.duration == 1.0, "duration should be end - start"


class TestAnnotationEdgeCases:
    """Edge case tests for Annotation entity."""

    def test_annotation_zero_duration(self) -> None:
        """Test annotation with zero duration is valid."""
        annotation = Annotation(
            id=AnnotationId(uuid4()),
            meeting_id=MeetingId(uuid4()),
            annotation_type=AnnotationType.NOTE,
            text="Instant note",
            start_time=5.0,
            end_time=5.0,
        )
        assert annotation.duration == 0.0, "duration should be 0.0 when start_time equals end_time"

    def test_annotation_empty_text(self) -> None:
        """Test annotation with empty text."""
        annotation = Annotation(
            id=AnnotationId(uuid4()),
            meeting_id=MeetingId(uuid4()),
            annotation_type=AnnotationType.NOTE,
            text="",
            start_time=0.0,
            end_time=1.0,
        )
        assert annotation.text == "", "empty text should be preserved as empty string"

    def test_annotation_unicode_text(self) -> None:
        """Test annotation with unicode text."""
        annotation = Annotation(
            id=AnnotationId(uuid4()),
            meeting_id=MeetingId(uuid4()),
            annotation_type=AnnotationType.NOTE,
            text="重要な点 🎯 café",
            start_time=0.0,
            end_time=1.0,
        )
        assert "🎯" in annotation.text, f"unicode emoji should be preserved in text, got: {annotation.text}"

    def test_annotation_many_segment_ids(self) -> None:
        """Test annotation with many segment IDs."""
        many_segments = list(range(100))
        annotation = Annotation(
            id=AnnotationId(uuid4()),
            meeting_id=MeetingId(uuid4()),
            annotation_type=AnnotationType.DECISION,
            text="Major decision",
            start_time=0.0,
            end_time=60.0,
            segment_ids=many_segments,
        )
        assert annotation.has_segments() is True, "has_segments should be True with many segments"
        assert len(annotation.segment_ids) == 100, "all segment_ids should be preserved"

    def test_annotation_very_long_duration(self) -> None:
        """Test annotation spanning long duration."""
        annotation = Annotation(
            id=AnnotationId(uuid4()),
            meeting_id=MeetingId(uuid4()),
            annotation_type=AnnotationType.NOTE,
            text="Long meeting note",
            start_time=0.0,
            end_time=TWO_HOURS_SECONDS,
        )
        assert annotation.duration == TWO_HOURS_SECONDS, f"duration should be {TWO_HOURS_SECONDS} seconds (2 hours), got {annotation.duration}"

    @pytest.mark.parametrize("annotation_type", list(AnnotationType))
    def test_annotation_all_types(self, annotation_type: AnnotationType) -> None:
        """Test all annotation types are valid."""
        meeting_id = MeetingId(uuid4())
        annotation = Annotation(
            id=AnnotationId(uuid4()),
            meeting_id=meeting_id,
            annotation_type=annotation_type,
            text=f"Test {annotation_type.name}",
            start_time=0.0,
            end_time=1.0,
        )
        assert annotation.annotation_type == annotation_type, f"annotation_type should match {annotation_type}, got {annotation.annotation_type}"

    def test_annotation_empty_segment_ids_list(self) -> None:
        """Test annotation with explicitly empty segment_ids."""
        annotation = Annotation(
            id=AnnotationId(uuid4()),
            meeting_id=MeetingId(uuid4()),
            annotation_type=AnnotationType.NOTE,
            text="No segments",
            start_time=0.0,
            end_time=1.0,
            segment_ids=[],
        )
        assert annotation.has_segments() is False, "empty segment_ids list should result in has_segments() returning False"
