"""Claim-id dedup at the SFTP pre-flight stage.

Schema: the ``submission_dedup`` table (defined on the main ``Base`` in
``cyclone.db``) records (claim_id, submitted_at). A re-submission of
the same claim_id within ``DEFAULT_WINDOW_DAYS`` (30) is rejected with
``DuplicateClaimError``. Past the window, the guard lets it through —
the operator may be retrying a 999-rejected file from >30 days ago,
which is a legitimate rebuild path.
"""
from __future__ import annotations

from datetime import datetime, timedelta, timezone

from sqlalchemy import select

from cyclone import db as cycl_db
from cyclone.db import SubmissionRecord
from cyclone.store.exceptions import DuplicateClaimError

DEFAULT_WINDOW_DAYS = 30


def record_submission(claim_id: str, submitted_at: datetime, db_url: str) -> None:
    """Upsert (claim_id, submitted_at). Idempotent on claim_id.

    ``db_url`` is accepted for back-compat with the original Task 8
    signature but ignored — sessions now flow through the process-wide
    ``cycl_db.SessionLocal()`` factory that ``db.init_db()`` set up.
    """
    del db_url  # signature-preserving; conftest wires the per-test DB
    with cycl_db.SessionLocal()() as session:
        session.merge(SubmissionRecord(
            claim_id=claim_id,
            submitted_at=submitted_at,
        ))
        session.commit()


def check_duplicate(
    claim_id: str,
    db_url: str | None = None,
    now: datetime | None = None,
    window_days: int = DEFAULT_WINDOW_DAYS,
) -> None:
    """Raise ``DuplicateClaimError`` if ``claim_id`` was submitted within the window.

    ``db_url`` is accepted for back-compat with the original Task 8
    signature but ignored — sessions flow through ``cycl_db.SessionLocal()``
    just like the rest of ``cyclone.store``. Tests that pass an explicit
    ``db_url`` keep working because ``cycl_db.SessionLocal()()`` points at
    the URL the conftest resolved under ``CYCLONE_DB_URL``.
    """
    del db_url  # signature-preserving
    if now is None:
        now = datetime.now(timezone.utc)
    cutoff = now - timedelta(days=window_days)
    with cycl_db.SessionLocal()() as session:
        row = session.scalars(
            select(SubmissionRecord).where(
                SubmissionRecord.claim_id == claim_id,
                SubmissionRecord.submitted_at >= cutoff,
            )
        ).first()
    if row is not None:
        raise DuplicateClaimError(claim_id, row.submitted_at)
