# #region V1ToV2Migration [C:3] [TYPE Module] [SEMANTICS migration,validation,data,idempotent]
# @BRIEF Migration script: v1 → v2 ValidationPolicy data. Converts existing dashboard_ids
#           JSON arrays to ValidationSource relational rows.
# @PRE  Database has both validation_policies and validation_sources tables.
# @POST Existing v1 dashboard_ids are converted to ValidationSource rows.
#       source_snapshot is set on each policy with the original dashboard_ids list.
# @SIDE_EFFECT Creates ValidationSource rows and updates source_snapshot on ValidationPolicy.
# @INVARIANT Idempotent — policies that already have sources are skipped.
# @RELATION DEPENDS_ON -> [ValidationPolicy]
# @RELATION DEPENDS_ON -> [ValidationSource]
"""
Migration script: v1 → v2 ValidationPolicy data.

Converts existing dashboard_ids JSON arrays to ValidationSource relational rows.
Safe to run multiple times (idempotent — skips policies that already have sources).

Usage::

    cd backend && source .venv/bin/activate
    python -m src.plugins.llm_analysis.migrations.v1_to_v2
"""

from datetime import UTC, datetime
from typing import Optional


def migrate_v1_to_v2(db_session=None):
    """Convert v1 ``dashboard_ids`` on ``ValidationPolicy`` → ``ValidationSource`` rows.

    Idempotent: skips policies that already have ``ValidationSource`` children.
    Sets ``source_snapshot`` to the original ``dashboard_ids`` list.

    Args:
        db_session: SQLAlchemy session. If ``None``, creates one via ``SessionLocal``.

    Side effects:
        - Creates ``ValidationSource`` rows (type="dashboard_id") for each dashboard_id.
        - Updates ``source_snapshot`` on each migrated policy.

    Returns:
        int: Number of policies migrated.
    """
    from ....models.llm import ValidationPolicy, ValidationSource

    if db_session is None:
        from ....core.database import SessionLocal
        db_session = SessionLocal()
        own_session = True
    else:
        own_session = False

    try:
        # Find all v1 policies that have dashboard_ids and don't already have sources
        policies = (
            db_session.query(ValidationPolicy)
            .filter(
                ValidationPolicy.dashboard_ids.isnot(None),
                ValidationPolicy.dashboard_ids != "[]",
                ValidationPolicy.dashboard_ids != [],
            )
            .all()
        )

        migrated_count = 0

        for policy in policies:
            # Skip if already migrated (has sources)
            existing_sources = (
                db_session.query(ValidationSource)
                .filter(ValidationSource.policy_id == policy.id)
                .count()
            )
            if existing_sources > 0:
                continue

            # Parse dashboard_ids (could be JSON string or already a list)
            dashboard_ids = policy.dashboard_ids
            if isinstance(dashboard_ids, str):
                import json
                dashboard_ids = json.loads(dashboard_ids)

            if not dashboard_ids or not isinstance(dashboard_ids, list):
                continue

            # Create ValidationSource rows
            for dashboard_id in dashboard_ids:
                source = ValidationSource(
                    type="dashboard_id",
                    value=str(dashboard_id),
                    status="valid",
                    policy_id=policy.id,
                )
                db_session.add(source)

            # Set source_snapshot with the original dashboard_ids list
            policy.source_snapshot = {
                "migrated_at": datetime.now(UTC).isoformat(),
                "original_dashboard_ids": dashboard_ids,
                "migration_version": "v1_to_v2",
            }

            migrated_count += 1

        db_session.commit()
        return migrated_count

    finally:
        if own_session:
            db_session.close()


def dry_run(db_session=None):
    """Preview how many policies would be migrated without making changes.

    Args:
        db_session: SQLAlchemy session.

    Returns:
        list[dict]: Policies that would be migrated (id, name, dashboard_ids).
    """
    from ....models.llm import ValidationPolicy, ValidationSource

    if db_session is None:
        from ....core.database import SessionLocal
        db_session = SessionLocal()
        own_session = True
    else:
        own_session = False

    try:
        policies = (
            db_session.query(ValidationPolicy)
            .filter(
                ValidationPolicy.dashboard_ids.isnot(None),
                ValidationPolicy.dashboard_ids != "[]",
                ValidationPolicy.dashboard_ids != [],
            )
            .all()
        )

        result = []
        for policy in policies:
            existing_sources = (
                db_session.query(ValidationSource)
                .filter(ValidationSource.policy_id == policy.id)
                .count()
            )
            if existing_sources == 0:
                dashboard_ids = policy.dashboard_ids
                if isinstance(dashboard_ids, str):
                    import json
                    dashboard_ids = json.loads(dashboard_ids)
                result.append({
                    "id": policy.id,
                    "name": policy.name,
                    "dashboard_ids": dashboard_ids,
                    "source_count": len(dashboard_ids) if dashboard_ids else 0,
                })

        return result

    finally:
        if own_session:
            db_session.close()


if __name__ == "__main__":
    import sys

    from ....core.database import SessionLocal

    args = set(sys.argv[1:])

    if "--dry-run" in args or "-n" in args:
        db = SessionLocal()
        try:
            pending = dry_run(db)
            if not pending:
                print("No v1 policies pending migration.")
            else:
                print(f"Would migrate {len(pending)} policies:")
                for p in pending:
                    print(f"  [{p['id']}] {p['name']} — {p['source_count']} source(s)")
        finally:
            db.close()
    else:
        db = SessionLocal()
        try:
            count = migrate_v1_to_v2(db)
            if count == 0:
                print("No v1 policies needed migration (all up-to-date).")
            else:
                print(f"Migration complete. {count} policy/policies migrated.")
        finally:
            db.close()
# #endregion V1ToV2Migration
