from __future__ import annotations

from dataclasses import dataclass

from rights_filter.analysis.internal_analyzer import InternalAnalyzer
from rights_filter.analysis.preprocessing import ImagePayload, PreprocessingError, build_external_derivative
from rights_filter.analysis.risk_scoring import RiskScorer
from rights_filter.domain.records import (
    AnalysisRun,
    Evidence,
    EvidenceSource,
    InMemoryRightsFilterRepository,
)
from rights_filter.integrations.cloud_vision_web_detection import CloudVisionWebDetectionAdapter
from rights_filter.integrations.external_policy import ExternalApiPolicy


@dataclass(frozen=True)
class SubmissionImage:
    submission_id: str
    image: ImagePayload


@dataclass(frozen=True)
class BatchSummary:
    processed: int = 0
    skipped_existing: int = 0
    external_skipped: int = 0
    failed: int = 0


class BatchAnalyzer:
    def __init__(
        self,
        repository: InMemoryRightsFilterRepository,
        internal_analyzer: InternalAnalyzer,
        external_adapter: CloudVisionWebDetectionAdapter,
        external_policy: ExternalApiPolicy,
        scorer: RiskScorer,
    ) -> None:
        self.repository = repository
        self.internal_analyzer = internal_analyzer
        self.external_adapter = external_adapter
        self.external_policy = external_policy
        self.scorer = scorer

    def run(
        self,
        submissions: list[SubmissionImage],
        analysis_version: str = "v1",
    ) -> BatchSummary:
        processed = 0
        skipped_existing = 0
        external_skipped = 0
        failed = 0

        for submission in submissions:
            if self.repository.has_analysis_run(
                submission.submission_id, analysis_version
            ):
                skipped_existing += 1
                continue

            run = AnalysisRun.for_submission(
                submission.submission_id, analysis_version
            )
            evidence: list[Evidence] = []
            try:
                evidence.extend(
                    self.internal_analyzer.analyze(
                        submission.submission_id, submission.image
                    )
                )
                derivative = build_external_derivative(submission.image)
                evidence.extend(
                    self.external_adapter.detect(
                        submission.submission_id,
                        derivative,
                        self.external_policy,
                    )
                )
            except PreprocessingError:
                # Count the failure and move on without saving a run. Falling
                # through previously double-counted the submission (failed AND
                # processed) and persisted a partial run whose presence made
                # has_analysis_run() skip the submission permanently on re-runs.
                failed += 1
                continue

            external_skipped += sum(
                1 for item in evidence if item.source == EvidenceSource.EXTERNAL_SKIPPED
            )
            for item in evidence:
                run.add_evidence(item)
            run.score = self.scorer.score(evidence)
            self.repository.save_analysis_run(run)
            processed += 1

        return BatchSummary(
            processed=processed,
            skipped_existing=skipped_existing,
            external_skipped=external_skipped,
            failed=failed,
        )
