"""
Tests for archived/deleted memory exclusion from retrieval (#1430).

Covers:
- apply_status_penalty filtering archived and deleted claims
- Vector search SQL filters (verified via the mixin logic)
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Dict, Optional
from unittest.mock import MagicMock

import pytest

from cortex.core.retrieval_search import apply_status_penalty
from cortex.core.retrieval_types import RetrievedItem


DEFAULT_PENALTIES = {
    "needs_review": 0.0,
    "rejected": 0.0,
}


def _make_item(
    status: str = "active",
    is_deleted: bool = False,
    score: float = 1.0,
    item_type: str = "claim",
) -> RetrievedItem:
    metadata: Dict[str, Any] = {"status": status}
    if is_deleted:
        metadata["is_deleted"] = True
    return RetrievedItem(
        item_type=item_type,
        item_id="test-id",
        content="test content",
        score=score,
        metadata=metadata,
    )


class TestApplyStatusPenalty:
    def test_active_claims_pass_through(self):
        items = [_make_item(status="active")]
        config = MagicMock()
        config.retrieval_status_penalties = None
        result = apply_status_penalty(config, items, DEFAULT_PENALTIES)
        assert len(result) == 1

    def test_archived_claims_excluded(self):
        items = [_make_item(status="archived")]
        config = MagicMock()
        config.retrieval_status_penalties = None
        result = apply_status_penalty(config, items, DEFAULT_PENALTIES)
        assert len(result) == 0

    def test_superseded_claims_excluded(self):
        items = [_make_item(status="superseded")]
        config = MagicMock()
        config.retrieval_status_penalties = None
        result = apply_status_penalty(config, items, DEFAULT_PENALTIES)
        assert len(result) == 0

    def test_deleted_claims_excluded(self):
        items = [_make_item(status="active", is_deleted=True)]
        config = MagicMock()
        config.retrieval_status_penalties = None
        result = apply_status_penalty(config, items, DEFAULT_PENALTIES)
        assert len(result) == 0

    def test_deleted_and_archived_both_excluded(self):
        items = [
            _make_item(status="active"),
            _make_item(status="archived"),
            _make_item(status="active", is_deleted=True),
            _make_item(status="rejected"),
        ]
        config = MagicMock()
        config.retrieval_status_penalties = None
        result = apply_status_penalty(config, items, DEFAULT_PENALTIES)
        assert len(result) == 1
        assert result[0].metadata["status"] == "active"

    def test_non_claim_items_pass_through(self):
        """Events and other types should not be filtered by status."""
        item = RetrievedItem(
            item_type="event",
            item_id="evt-1",
            content="some event",
            score=1.0,
            metadata={"status": "archived"},
        )
        config = MagicMock()
        config.retrieval_status_penalties = None
        result = apply_status_penalty(config, [item], DEFAULT_PENALTIES)
        assert len(result) == 1

    def test_needs_review_excluded(self):
        items = [_make_item(status="needs_review")]
        config = MagicMock()
        config.retrieval_status_penalties = None
        result = apply_status_penalty(config, items, DEFAULT_PENALTIES)
        assert len(result) == 0

    def test_mixed_statuses_correct_filtering(self):
        items = [
            _make_item(status="active", score=0.9),
            _make_item(status="needs_review", score=0.8),
            _make_item(status="archived", score=0.7),
            _make_item(status="superseded", score=0.6),
            _make_item(status="rejected", score=0.5),
            _make_item(status="active", is_deleted=True, score=0.4),
        ]
        config = MagicMock()
        config.retrieval_status_penalties = None
        result = apply_status_penalty(config, items, DEFAULT_PENALTIES)
        # Only the first active, non-deleted item should survive
        assert len(result) == 1
        # Score may have penalty applied for "active" status (default 0.5)
        assert result[0].metadata["status"] == "active"
        assert not result[0].metadata.get("is_deleted")
