"""Scheduled task: monthly poll of Rosreestr open-data portal for a new quarter (#888).

Delegates detect+alert logic to app.services.rosreestr_poll.poll_rosreestr_new_quarter().
Wired into the in-app scheduler as source='rosreestr_quarter_poll'. Triggered monthly via
the scrape_schedules seed (migration 096).

SCOPE: detect availability + log actionable alert ONLY.
Does NOT download the multi-GB ZIP or shell out to the loaders.
When available=True, the operator runs manually:
  data/sql/02_load_all_quarters.sh
  tradein-mvp/deploy/import-rosreestr.sh

Mirrors tasks/sber_index_pull.py: thin async wrapper around the service,
heartbeat → delegate → mark_done/mark_failed.
"""

from __future__ import annotations

import logging
import time
from dataclasses import dataclass, field

from sqlalchemy.orm import Session

from app.services import scrape_runs as runs_mod
from app.services.rosreestr_poll import poll_rosreestr_new_quarter

logger = logging.getLogger(__name__)

__all__ = [
    "RosreestrQuarterPollResult",
    "run_rosreestr_quarter_poll",
]


@dataclass
class RosreestrQuarterPollResult:
    """Result from a scheduled Rosreestr quarter-poll run."""

    available: bool = False
    year: int = 0
    quarter: int = 0
    duration_sec: float = field(default=0.0)


async def run_rosreestr_quarter_poll(
    db: Session,
    *,
    run_id: int,
    params: dict,  # type: ignore[type-arg]
) -> RosreestrQuarterPollResult:
    """Execute Rosreestr quarter poll with run lifecycle management.

    Wraps poll_rosreestr_new_quarter(), emitting heartbeat before the check
    and marking the scrape_run as done/failed on completion.

    Params (from default_params jsonb in scrape_schedules):
        interval_days: int — informational only (scheduler uses next_run_at arithmetic).
    """
    counters: dict[str, int] = {
        "available": 0,
        "year": 0,
        "quarter": 0,
    }
    started_at = time.monotonic()

    try:
        runs_mod.update_heartbeat(db, run_id, counters)

        result_dict = await poll_rosreestr_new_quarter(db)

        available = bool(result_dict.get("available", False))
        year = int(result_dict.get("year", 0))
        quarter = int(result_dict.get("quarter", 0))
        duration_sec = time.monotonic() - started_at

        counters = {
            "available": int(available),
            "year": year,
            "quarter": quarter,
            "duration_sec": int(duration_sec),
        }
        runs_mod.mark_done(db, run_id, counters)
        logger.info(
            "rosreestr_quarter_poll run_id=%d done — available=%s Q%d %d %.1fs",
            run_id,
            available,
            quarter,
            year,
            duration_sec,
        )
        return RosreestrQuarterPollResult(
            available=available,
            year=year,
            quarter=quarter,
            duration_sec=duration_sec,
        )

    except Exception as exc:
        logger.exception("rosreestr_quarter_poll run_id=%d failed", run_id)
        runs_mod.mark_failed(db, run_id, str(exc)[:1000], counters)
        raise
