"""Job processor: run validation for a claimed job."""

from __future__ import annotations

import asyncio
import logging
from functools import partial
from typing import Any

from pycharter.worker.job_sources.base import JobSource
from pycharter.worker.models import ClaimedJob

logger = logging.getLogger(__name__)


class JobProcessor:
    """Processes a single claimed job: validate then complete/fail."""

    def __init__(self, job_source: JobSource, db_url: str) -> None:
        self._job_source = job_source
        self._db_url = db_url

    async def process_one(self, claimed: ClaimedJob) -> None:
        """Run validation for the claimed job; complete or fail in the source."""
        logger.info(
            "Processing job %s: contract=%s@%s data_source=%s (attempt %d/%d)",
            claimed.event_id,
            claimed.contract_name,
            claimed.contract_version,
            claimed.data_source,
            claimed.attempt,
            claimed.max_attempts,
        )
        try:
            result = await self._run_validation(claimed)
            await self._job_source.complete(claimed.event_id, result=result)
            logger.info("Job %s completed", claimed.event_id)
        except Exception as e:
            logger.exception("Job %s failed: %s", claimed.event_id, e)
            retry = claimed.attempt < claimed.max_attempts
            await self._job_source.fail(claimed.event_id, str(e), retry=retry)

    async def _run_validation(self, claimed: ClaimedJob) -> dict[str, Any]:
        """Run validation in an executor (CPU-bound work)."""
        loop = asyncio.get_running_loop()
        return await loop.run_in_executor(
            None,
            partial(self._validate_sync, claimed),
        )

    def _validate_sync(self, claimed: ClaimedJob) -> dict[str, Any]:
        """Synchronous validation using QualityCheck."""
        from pycharter.db.models.base import get_session
        from pycharter.quality.check import QualityCheck
        from pycharter.quality.models import QualityCheckOptions

        store = self._get_store()
        session = get_session(self._db_url)
        try:
            quality_check = QualityCheck(store=store, db_session=session)
            options = QualityCheckOptions(
                data_source=claimed.data_source,
                record_violations=True,
                calculate_metrics=True,
                **(claimed.options or {}),
            )

            report = quality_check.run(
                contract_name=claimed.contract_name,
                contract_version=claimed.contract_version,
                data=claimed.data_source,
                options=options,
            )

            return {
                "total_count": report.record_count,
                "valid_count": report.valid_count,
                "invalid_count": report.invalid_count,
                "quality_score": (
                    report.quality_score.overall_score if report.quality_score else 0.0
                ),
                "violation_count": report.violation_count,
                "data_source": claimed.data_source,
                "passed": report.passed,
            }
        finally:
            session.close()
            if store:
                store.disconnect()

    def _get_store(self):
        """Get metadata store from db_url."""
        from pycharter.metadata_store import PostgresMetadataStore, SQLiteMetadataStore

        if self._db_url.startswith("sqlite://"):
            store = SQLiteMetadataStore()
        else:
            store = PostgresMetadataStore()
        store.connect()
        return store
