from rights_filter.analysis.face_person_detection import HeuristicFacePersonDetector
from rights_filter.analysis.fingerprints import FingerprintService
from rights_filter.analysis.internal_analyzer import InternalAnalyzer
from rights_filter.analysis.preprocessing import ImagePayload
from rights_filter.analysis.risk_scoring import RiskScorer
from rights_filter.domain.records import InMemoryRightsFilterRepository
from rights_filter.integrations.cloud_vision_web_detection import (
    CloudVisionWebDetectionAdapter,
    FakeWebDetectionClient,
)
from rights_filter.integrations.external_policy import ExternalApiPolicy
from rights_filter.jobs.batch_analyzer import BatchAnalyzer, SubmissionImage


def build_batch(policy=None):
    repo = InMemoryRightsFilterRepository()
    internal = InternalAnalyzer(repo, FingerprintService(), HeuristicFacePersonDetector())
    external = CloudVisionWebDetectionAdapter(FakeWebDetectionClient())
    return BatchAnalyzer(
        repository=repo,
        internal_analyzer=internal,
        external_adapter=external,
        external_policy=policy or ExternalApiPolicy(disabled=True),
        scorer=RiskScorer(),
    )


def test_batch_processes_all_submissions_internal_only_when_external_disabled():
    batch = build_batch()
    submissions = [
        SubmissionImage("s1", ImagePayload(b"image one FACE", 100, 100, {})),
        SubmissionImage("s2", ImagePayload(b"image two", 100, 100, {})),
    ]

    summary = batch.run(submissions)

    assert summary.processed == 2
    assert summary.external_skipped == 2
    assert batch.repository.latest_score_for_submission("s1") is not None
    assert batch.repository.latest_score_for_submission("s2") is not None


def test_batch_is_idempotent_for_same_submission_and_version():
    batch = build_batch()
    submissions = [SubmissionImage("s1", ImagePayload(b"image one", 100, 100, {}))]

    first = batch.run(submissions, analysis_version="v1")
    second = batch.run(submissions, analysis_version="v1")

    assert first.processed == 1
    assert second.skipped_existing == 1
    assert len(batch.repository.analysis_runs_for_submission("s1")) == 1


def test_failed_submission_is_counted_once_and_remains_retryable():
    batch = build_batch()
    # Non-empty bytes (so internal analysis runs) but a non-positive dimension,
    # which makes build_external_derivative raise PreprocessingError.
    submissions = [SubmissionImage("s1", ImagePayload(b"not-an-image", 0, 100, {}))]

    first = batch.run(submissions)

    # Counted as failed only — not also processed — and no partial run persisted.
    assert first.failed == 1
    assert first.processed == 0
    assert batch.repository.latest_score_for_submission("s1") is None
    assert not batch.repository.has_analysis_run("s1", "v1")

    # Because nothing was saved, a later batch re-attempts rather than skipping.
    second = batch.run(submissions)
    assert second.failed == 1
    assert second.skipped_existing == 0
