"""issues + systems: task_kind=issue, systems, record_systems, arose_from_id

Revision ID: 0065
Revises: 0064
Create Date: 2026-06-14

Adds the corrective-work 'issue' task_kind (same-change CHECK expand per the
'new CHECK-enum values need a same-change migration' rule), a per-project
self-describing System entity, a many-to-many record<->system join (any
note/task/issue), and an issue->originating-task provenance FK.
"""
from alembic import op
import sqlalchemy as sa


revision = "0065"
down_revision = "0064"
branch_labels = None
depends_on = None


def upgrade() -> None:
    # 1. task_kind gains 'issue' (corrective work). DROP+ADD the CHECK in the
    #    same change that introduces the value.
    op.drop_constraint("notes_task_kind_check", "notes", type_="check")
    op.create_check_constraint(
        "notes_task_kind_check", "notes", "task_kind IN ('work','plan','issue')",
    )

    # 2. Provenance: an issue can point back at the task/feature it arose from.
    #    Distinct from parent_id (sub-task hierarchy).
    op.add_column("notes", sa.Column("arose_from_id", sa.Integer(), nullable=True))
    op.create_foreign_key(
        "fk_notes_arose_from_id", "notes", "notes",
        ["arose_from_id"], ["id"], ondelete="SET NULL",
    )
    op.create_index("ix_notes_arose_from_id", "notes", ["arose_from_id"])

    # 3. systems: per-project, reusable, self-describing subsystem/area.
    op.create_table(
        "systems",
        sa.Column("id", sa.Integer(), primary_key=True),
        sa.Column(
            "user_id", sa.Integer(),
            sa.ForeignKey("users.id", ondelete="CASCADE"), nullable=False,
        ),
        sa.Column(
            "project_id", sa.Integer(),
            sa.ForeignKey("projects.id", ondelete="CASCADE"), nullable=False,
        ),
        sa.Column("name", sa.Text(), nullable=False, server_default=""),
        sa.Column("description", sa.Text(), nullable=True),
        sa.Column("color", sa.Text(), nullable=True),
        sa.Column("status", sa.Text(), nullable=False, server_default="active"),
        sa.Column("order_index", sa.Integer(), nullable=False, server_default="0"),
        sa.Column(
            "created_at", sa.DateTime(timezone=True), nullable=False,
            server_default=sa.text("now()"),
        ),
        sa.Column(
            "updated_at", sa.DateTime(timezone=True), nullable=False,
            server_default=sa.text("now()"),
        ),
        sa.Column("deleted_at", sa.DateTime(timezone=True), nullable=True),
        sa.Column("deleted_batch_id", sa.Text(), nullable=True),
    )
    op.create_index("ix_systems_project_id", "systems", ["project_id"])
    op.create_check_constraint(
        "systems_status_check", "systems", "status IN ('active','archived')",
    )

    # 4. record_systems: M2M join — any note/task/issue <-> system.
    op.create_table(
        "record_systems",
        sa.Column("id", sa.Integer(), primary_key=True),
        sa.Column(
            "note_id", sa.Integer(),
            sa.ForeignKey("notes.id", ondelete="CASCADE"), nullable=False,
        ),
        sa.Column(
            "system_id", sa.Integer(),
            sa.ForeignKey("systems.id", ondelete="CASCADE"), nullable=False,
        ),
        sa.Column(
            "created_at", sa.DateTime(timezone=True), nullable=False,
            server_default=sa.text("now()"),
        ),
        sa.UniqueConstraint("note_id", "system_id", name="uq_record_systems_note_system"),
    )
    op.create_index("ix_record_systems_note_id", "record_systems", ["note_id"])
    op.create_index("ix_record_systems_system_id", "record_systems", ["system_id"])


def downgrade() -> None:
    op.drop_table("record_systems")
    op.drop_table("systems")
    op.drop_index("ix_notes_arose_from_id", table_name="notes")
    op.drop_constraint("fk_notes_arose_from_id", "notes", type_="foreignkey")
    op.drop_column("notes", "arose_from_id")
    op.drop_constraint("notes_task_kind_check", "notes", type_="check")
    op.create_check_constraint(
        "notes_task_kind_check", "notes", "task_kind IN ('work','plan')",
    )
