"""initial schema

Revision ID: 0b9c1d2e3f4a
Revises:
Create Date: 2026-04-23 00:00:00.000000+00:00

Idempotent: uses CREATE TABLE IF NOT EXISTS so it is safe to run
against a DB that was already bootstrapped via SQLAlchemy create_all().
"""

from typing import Sequence, Union

from alembic import op

revision: str = '0b9c1d2e3f4a'
down_revision: Union[str, None] = None
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
    op.execute("""
    CREATE TABLE IF NOT EXISTS duniter_identities (
        id UUID PRIMARY KEY,
        address VARCHAR(64) NOT NULL,
        display_name VARCHAR(128),
        wot_status VARCHAR(32) NOT NULL DEFAULT 'unknown',
        is_smith BOOLEAN NOT NULL DEFAULT FALSE,
        is_techcomm BOOLEAN NOT NULL DEFAULT FALSE,
        created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
    )
    """)
    op.execute("CREATE UNIQUE INDEX IF NOT EXISTS ix_duniter_identities_address ON duniter_identities (address)")

    op.execute("""
    CREATE TABLE IF NOT EXISTS sessions (
        id UUID PRIMARY KEY,
        token_hash VARCHAR(128) NOT NULL,
        identity_id UUID NOT NULL REFERENCES duniter_identities(id),
        created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        expires_at TIMESTAMPTZ NOT NULL
    )
    """)
    op.execute("CREATE UNIQUE INDEX IF NOT EXISTS ix_sessions_token_hash ON sessions (token_hash)")

    op.execute("""
    CREATE TABLE IF NOT EXISTS organizations (
        id UUID PRIMARY KEY,
        name VARCHAR(128) NOT NULL,
        slug VARCHAR(128) NOT NULL,
        org_type VARCHAR(64) NOT NULL DEFAULT 'community',
        is_transparent BOOLEAN NOT NULL DEFAULT FALSE,
        color VARCHAR(32),
        icon VARCHAR(64),
        description TEXT,
        created_at TIMESTAMPTZ NOT NULL DEFAULT now()
    )
    """)
    op.execute("CREATE UNIQUE INDEX IF NOT EXISTS ix_organizations_slug ON organizations (slug)")

    op.execute("""
    CREATE TABLE IF NOT EXISTS org_members (
        id UUID PRIMARY KEY,
        org_id UUID NOT NULL REFERENCES organizations(id),
        identity_id UUID NOT NULL REFERENCES duniter_identities(id),
        role VARCHAR(32) NOT NULL DEFAULT 'member',
        created_at TIMESTAMPTZ NOT NULL DEFAULT now()
    )
    """)

    op.execute("""
    CREATE TABLE IF NOT EXISTS formula_configs (
        id UUID PRIMARY KEY,
        name VARCHAR(128) NOT NULL,
        description TEXT,
        duration_days INTEGER NOT NULL DEFAULT 30,
        majority_pct INTEGER NOT NULL DEFAULT 50,
        base_exponent FLOAT NOT NULL DEFAULT 0.1,
        gradient_exponent FLOAT NOT NULL DEFAULT 0.2,
        constant_base FLOAT NOT NULL DEFAULT 0.0,
        smith_exponent FLOAT,
        techcomm_exponent FLOAT,
        nuanced_min_participants INTEGER,
        nuanced_threshold_pct INTEGER,
        created_at TIMESTAMPTZ NOT NULL DEFAULT now()
    )
    """)

    op.execute("""
    CREATE TABLE IF NOT EXISTS voting_protocols (
        id UUID PRIMARY KEY,
        name VARCHAR(128) NOT NULL,
        description TEXT,
        vote_type VARCHAR(32) NOT NULL,
        formula_config_id UUID NOT NULL REFERENCES formula_configs(id),
        mode_params VARCHAR(64),
        is_meta_governed BOOLEAN NOT NULL DEFAULT FALSE,
        created_at TIMESTAMPTZ NOT NULL DEFAULT now()
    )
    """)

    op.execute("""
    CREATE TABLE IF NOT EXISTS sanctuary_entries (
        id UUID PRIMARY KEY,
        entry_type VARCHAR(64) NOT NULL,
        reference_id UUID NOT NULL,
        title VARCHAR(256),
        content_hash VARCHAR(128) NOT NULL,
        ipfs_cid VARCHAR(128),
        chain_tx_hash VARCHAR(128),
        chain_block INTEGER,
        metadata_json TEXT,
        created_at TIMESTAMPTZ NOT NULL DEFAULT now()
    )
    """)

    op.execute("""
    CREATE TABLE IF NOT EXISTS blockchain_cache (
        id UUID PRIMARY KEY,
        cache_key VARCHAR(256) NOT NULL,
        cache_value JSON NOT NULL,
        fetched_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        expires_at TIMESTAMPTZ NOT NULL
    )
    """)
    op.execute("CREATE UNIQUE INDEX IF NOT EXISTS ix_blockchain_cache_cache_key ON blockchain_cache (cache_key)")

    op.execute("""
    CREATE TABLE IF NOT EXISTS documents (
        id UUID PRIMARY KEY,
        slug VARCHAR(128) NOT NULL,
        title VARCHAR(256) NOT NULL,
        doc_type VARCHAR(64) NOT NULL,
        version VARCHAR(32) NOT NULL DEFAULT '0.1.0',
        status VARCHAR(32) NOT NULL DEFAULT 'draft',
        description TEXT,
        ipfs_cid VARCHAR(128),
        chain_anchor VARCHAR(128),
        genesis_json TEXT,
        created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
    )
    """)
    op.execute("CREATE UNIQUE INDEX IF NOT EXISTS ix_documents_slug ON documents (slug)")

    op.execute("""
    CREATE TABLE IF NOT EXISTS decisions (
        id UUID PRIMARY KEY,
        title VARCHAR(256) NOT NULL,
        description TEXT,
        context TEXT,
        decision_type VARCHAR(64) NOT NULL,
        status VARCHAR(32) NOT NULL DEFAULT 'draft',
        voting_protocol_id UUID REFERENCES voting_protocols(id),
        created_by_id UUID REFERENCES duniter_identities(id),
        created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
    )
    """)

    op.execute("""
    CREATE TABLE IF NOT EXISTS item_versions (
        id UUID PRIMARY KEY,
        item_id UUID NOT NULL,
        proposed_text TEXT NOT NULL,
        diff_text TEXT,
        rationale TEXT,
        status VARCHAR(32) NOT NULL DEFAULT 'proposed',
        decision_id UUID REFERENCES decisions(id),
        proposed_by_id UUID REFERENCES duniter_identities(id),
        created_at TIMESTAMPTZ NOT NULL DEFAULT now()
    )
    """)

    op.execute("""
    CREATE TABLE IF NOT EXISTS vote_sessions (
        id UUID PRIMARY KEY,
        decision_id UUID REFERENCES decisions(id),
        item_version_id UUID REFERENCES item_versions(id),
        voting_protocol_id UUID NOT NULL REFERENCES voting_protocols(id),
        wot_size INTEGER NOT NULL DEFAULT 0,
        smith_size INTEGER NOT NULL DEFAULT 0,
        techcomm_size INTEGER NOT NULL DEFAULT 0,
        starts_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        ends_at TIMESTAMPTZ NOT NULL,
        status VARCHAR(32) NOT NULL DEFAULT 'open',
        votes_for INTEGER NOT NULL DEFAULT 0,
        votes_against INTEGER NOT NULL DEFAULT 0,
        votes_total INTEGER NOT NULL DEFAULT 0,
        smith_votes_for INTEGER NOT NULL DEFAULT 0,
        techcomm_votes_for INTEGER NOT NULL DEFAULT 0,
        threshold_required FLOAT NOT NULL DEFAULT 0.0,
        result VARCHAR(32),
        chain_recorded BOOLEAN NOT NULL DEFAULT FALSE,
        chain_tx_hash VARCHAR(128),
        created_at TIMESTAMPTZ NOT NULL DEFAULT now()
    )
    """)

    op.execute("""
    CREATE TABLE IF NOT EXISTS decision_steps (
        id UUID PRIMARY KEY,
        decision_id UUID NOT NULL REFERENCES decisions(id),
        step_order INTEGER NOT NULL,
        step_type VARCHAR(32) NOT NULL,
        title VARCHAR(256),
        description TEXT,
        status VARCHAR(32) NOT NULL DEFAULT 'pending',
        vote_session_id UUID REFERENCES vote_sessions(id),
        outcome TEXT,
        created_at TIMESTAMPTZ NOT NULL DEFAULT now()
    )
    """)

    op.execute("""
    CREATE TABLE IF NOT EXISTS document_items (
        id UUID PRIMARY KEY,
        document_id UUID NOT NULL REFERENCES documents(id),
        position VARCHAR(16) NOT NULL,
        item_type VARCHAR(32) NOT NULL DEFAULT 'clause',
        title VARCHAR(256),
        current_text TEXT NOT NULL,
        voting_protocol_id UUID REFERENCES voting_protocols(id),
        sort_order INTEGER NOT NULL DEFAULT 0,
        section_tag VARCHAR(64),
        inertia_preset VARCHAR(16) NOT NULL DEFAULT 'standard',
        is_permanent_vote BOOLEAN NOT NULL DEFAULT TRUE,
        created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
    )
    """)

    op.execute("""
    DO $$
    BEGIN
        IF NOT EXISTS (
            SELECT 1 FROM information_schema.table_constraints
            WHERE constraint_name = 'item_versions_item_id_fkey'
            AND table_name = 'item_versions'
        ) THEN
            ALTER TABLE item_versions
                ADD CONSTRAINT item_versions_item_id_fkey
                FOREIGN KEY (item_id) REFERENCES document_items(id);
        END IF;
    END $$
    """)

    op.execute("""
    CREATE TABLE IF NOT EXISTS votes (
        id UUID PRIMARY KEY,
        session_id UUID NOT NULL REFERENCES vote_sessions(id),
        voter_id UUID NOT NULL REFERENCES duniter_identities(id),
        vote_value VARCHAR(32) NOT NULL,
        nuanced_level INTEGER,
        comment TEXT,
        signature TEXT NOT NULL,
        signed_payload TEXT NOT NULL,
        voter_wot_status VARCHAR(32) NOT NULL DEFAULT 'member',
        voter_is_smith BOOLEAN NOT NULL DEFAULT FALSE,
        voter_is_techcomm BOOLEAN NOT NULL DEFAULT FALSE,
        is_active BOOLEAN NOT NULL DEFAULT TRUE,
        created_at TIMESTAMPTZ NOT NULL DEFAULT now()
    )
    """)

    op.execute("""
    CREATE TABLE IF NOT EXISTS mandates (
        id UUID PRIMARY KEY,
        title VARCHAR(256) NOT NULL,
        description TEXT,
        mandate_type VARCHAR(64) NOT NULL,
        status VARCHAR(32) NOT NULL DEFAULT 'draft',
        mandatee_id UUID REFERENCES duniter_identities(id),
        decision_id UUID REFERENCES decisions(id),
        starts_at TIMESTAMPTZ,
        ends_at TIMESTAMPTZ,
        created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
        updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
    )
    """)

    op.execute("""
    CREATE TABLE IF NOT EXISTS mandate_steps (
        id UUID PRIMARY KEY,
        mandate_id UUID NOT NULL REFERENCES mandates(id),
        step_order INTEGER NOT NULL,
        step_type VARCHAR(32) NOT NULL,
        title VARCHAR(256),
        description TEXT,
        status VARCHAR(32) NOT NULL DEFAULT 'pending',
        vote_session_id UUID REFERENCES vote_sessions(id),
        outcome TEXT,
        created_at TIMESTAMPTZ NOT NULL DEFAULT now()
    )
    """)


def downgrade() -> None:
    # Intentionally left empty — dropping the initial schema would destroy all data.
    pass
