"""ocr_text table and Postgres FTS

Revision ID: 0004_ocr_fts
Revises: 0003_pgvector_embeddings
Create Date: 2026-04-10

Create ocr_text table for storing OCR results. Add a tsvector column
to photos for unified full-text search (filename + user_title +
user_notes) with a GIN index. OCR text is rolled up into a materialized
view or joined at query time.
"""
from typing import Sequence, Union

from alembic import op

revision: str = "0004_ocr_fts"
down_revision: Union[str, None] = "0003_pgvector_embeddings"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
    # ── ocr_text table ────────────────────────────────────────────────
    op.execute("""
        CREATE TABLE IF NOT EXISTS ocr_text (
            id VARCHAR PRIMARY KEY,
            photo_id VARCHAR NOT NULL REFERENCES photos(id) ON DELETE CASCADE,
            text TEXT NOT NULL,
            language VARCHAR(8) DEFAULT '',
            confidence FLOAT,
            bbox JSONB,
            created_at TIMESTAMPTZ DEFAULT now()
        )
    """)
    op.execute("CREATE INDEX IF NOT EXISTS ix_ocr_text_photo_id ON ocr_text(photo_id)")

    # ── tsvector column on photos ─────────────────────────────────────
    op.execute("ALTER TABLE photos ADD COLUMN IF NOT EXISTS search_vector tsvector")
    op.execute("CREATE INDEX IF NOT EXISTS ix_photos_search_vector ON photos USING GIN (search_vector)")

    # Trigger to auto-update search_vector on INSERT/UPDATE
    op.execute("""
        CREATE OR REPLACE FUNCTION photos_search_vector_update() RETURNS trigger AS $$
        BEGIN
            NEW.search_vector :=
                setweight(to_tsvector('english', coalesce(NEW.filename, '')), 'A') ||
                setweight(to_tsvector('english', coalesce(NEW.user_title, '')), 'A') ||
                setweight(to_tsvector('english', coalesce(NEW.user_notes, '')), 'B');
            RETURN NEW;
        END
        $$ LANGUAGE plpgsql;
    """)
    op.execute("""
        DO $$
        BEGIN
            IF NOT EXISTS (
                SELECT 1 FROM pg_trigger WHERE tgname = 'photos_search_vector_trigger'
            ) THEN
                CREATE TRIGGER photos_search_vector_trigger
                BEFORE INSERT OR UPDATE OF filename, user_title, user_notes
                ON photos
                FOR EACH ROW
                EXECUTE FUNCTION photos_search_vector_update();
            END IF;
        END $$;
    """)

    # Backfill existing rows
    op.execute("""
        UPDATE photos SET search_vector =
            setweight(to_tsvector('english', coalesce(filename, '')), 'A') ||
            setweight(to_tsvector('english', coalesce(user_title, '')), 'A') ||
            setweight(to_tsvector('english', coalesce(user_notes, '')), 'B')
    """)


def downgrade() -> None:
    op.execute("DROP TRIGGER IF EXISTS photos_search_vector_trigger ON photos")
    op.execute("DROP FUNCTION IF EXISTS photos_search_vector_update()")
    op.execute("DROP INDEX IF EXISTS ix_photos_search_vector")
    op.execute("ALTER TABLE photos DROP COLUMN IF EXISTS search_vector")
    op.execute("DROP TABLE IF EXISTS ocr_text")
