"""
Enrichment archival helper.

Standalone functions to archive enrichment data to the vault after successful writes.
Can be called from any enrichment flow (SFDC, Sheets, etc.).
"""

import logging
from typing import Any, Dict, List

import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import insert
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession

from ..model_defs.enrichment_vault import EnrichmentVault
from ..models import EnrichmentUsage

logger = logging.getLogger(__name__)


async def should_archive(db: AsyncSession, account_id: str) -> bool:
    """Check if account has enrichment archival enabled."""
    try:
        row = await db.execute(
            sa.text("SELECT enrichment_archival_enabled FROM accounts WHERE id = :aid"),
            {"aid": account_id},
        )
        val = row.scalar_one_or_none()
        return bool(val) if val is not None else True
    except Exception as e:
        logger.warning(
            f"Failed to check archival setting for account {account_id}: {e}"
        )
        return True  # Default to enabled if check fails


async def archive_enrichment_fields(
    db: AsyncSession,
    *,
    usage_id: int,
    account_id: str,
    sfdc_object: str,
    enriched_records: List[Dict[str, Any]],
    successful_ids: List[str],
    before_values: Dict[str, Dict[str, Any]] = None,
) -> int:
    """
    Archive enriched fields to vault (field-level).

    Args:
        db: Database session
        usage_id: EnrichmentUsage.id (ledger reference)
        account_id: Account ID
        sfdc_object: SFDC object type (Lead, Contact, Account, SheetRow)
        enriched_records: Records that were written [{"Id":"003...", "Email":"x", "Title":"y", ...}]
        successful_ids: List of IDs that were successfully written
        before_values: Optional dict of {record_id: {field: value}} for before state

    Returns:
        Number of vault rows archived
    """
    if not enriched_records or not successful_ids:
        return 0

    before_values = before_values or {}
    success_set = set(successful_ids)

    rows = []
    for rec in enriched_records:
        rid = rec.get("Id") or rec.get("id")
        if not rid or rid not in success_set:
            continue  # Only archive successful writes

        before_map = before_values.get(rid, {})
        for field_name, value_after in rec.items():
            if field_name in ("Id", "id"):
                continue  # Skip ID field

            value_before = before_map.get(field_name)
            rows.append(
                {
                    "usage_id": usage_id,
                    "account_id": account_id,
                    "sfdc_object": sfdc_object,
                    "sfdc_record_id": rid,
                    "field_name": field_name,
                    "value_before": None if value_before is None else str(value_before),
                    "value_after": "" if value_after is None else str(value_after),
                    "provider_confidence": None,
                }
            )

    if not rows:
        logger.debug(f"No rows to archive for usage_id={usage_id}")
        return 0

    # Use INSERT ... ON CONFLICT DO NOTHING for idempotency
    stmt = insert(EnrichmentVault).values(rows)
    stmt = stmt.on_conflict_do_nothing(
        index_elements=["usage_id", "sfdc_record_id", "field_name"]
    )

    try:
        await db.execute(stmt)

        # Mark usage row as having archived data
        await db.execute(
            sa.update(EnrichmentUsage)
            .where(EnrichmentUsage.id == usage_id)
            .values(has_archived_data=True)
        )

        logger.info(
            f"Archived {len(rows)} field-level records to vault for usage_id={usage_id}"
        )
        return len(rows)

    except IntegrityError as e:
        # Safe to ignore - happens on retry with same idempotency key
        logger.debug(f"Vault archive conflict (expected on retry): {e}")
        return 0
    except Exception as e:
        logger.error(f"Failed to archive to vault for usage_id={usage_id}: {e}")
        return 0
