"""Add custom_reports table

Creates the custom_reports table for storing extracted report data from
custom severity bugs. Includes backfill from existing bugs.raw_data.

Revision ID: e2a63f33f729
Revises: 8699d94758fb
Create Date: 2026-02-17 15:56:12.923637

"""

import json
from collections.abc import Sequence

import sqlalchemy as sa

from alembic import op

# revision identifiers, used by Alembic.
revision: str = "e2a63f33f729"
down_revision: str | Sequence[str] | None = "8699d94758fb"  # pragma: allowlist secret
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None

# Default fields to exclude (same as config.CUSTOM_REPORT_EXCLUDE_FIELDS)
EXCLUDE_FIELDS = {"plain_text_interactions"}


def upgrade() -> None:
    """Upgrade schema."""
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table(
        "custom_reports",
        sa.Column("bug_id", sa.Integer(), nullable=False),
        sa.Column("configuration_id", sa.Integer(), nullable=True),
        sa.Column("report_data", sa.Text(), nullable=False),
        sa.ForeignKeyConstraint(
            ["bug_id"],
            ["bugs.id"],
        ),
        sa.PrimaryKeyConstraint("bug_id"),
    )
    with op.batch_alter_table("custom_reports", schema=None) as batch_op:
        batch_op.create_index(
            batch_op.f("ix_custom_reports_configuration_id"),
            ["configuration_id"],
            unique=False,
        )

    # ### end Alembic commands ###

    # Backfill: extract report.content.data + configuration_id from bugs.raw_data
    conn = op.get_bind()
    rows = conn.execute(
        sa.text("""
            SELECT id,
                   json_extract(raw_data, '$.report.content.data') as rdata,
                   json_extract(raw_data, '$.report.custom_report_configuration_id') as config_id
            FROM bugs
            WHERE json_extract(raw_data, '$.report.content.data') IS NOT NULL
        """)
    )
    for row in rows:
        try:
            data_array = json.loads(row.rdata)
        except (json.JSONDecodeError, TypeError):
            continue

        flat = {
            item["key"]: item.get("value", "")
            for item in data_array
            if isinstance(item, dict) and "key" in item and item["key"] not in EXCLUDE_FIELDS
        }
        if flat:
            conn.execute(
                sa.text(
                    "INSERT OR IGNORE INTO custom_reports (bug_id, configuration_id, report_data) "
                    "VALUES (:bid, :cid, :rd)"
                ),
                {"bid": row.id, "cid": row.config_id, "rd": json.dumps(flat)},
            )


def downgrade() -> None:
    """Downgrade schema."""
    # ### commands auto generated by Alembic - please adjust! ###
    with op.batch_alter_table("custom_reports", schema=None) as batch_op:
        batch_op.drop_index(batch_op.f("ix_custom_reports_configuration_id"))

    op.drop_table("custom_reports")
    # ### end Alembic commands ###
