"""Initial schema – tutte le tabelle PecFlow Fase 1

Revision ID: 0001
Revises:
Create Date: 2026-03-18 00:00:00.000000
"""

from alembic import op

revision = "0001"
down_revision = None
branch_labels = None
depends_on = None


def upgrade() -> None:
    # Esegui l'intero schema come SQL puro (più affidabile con ENUM types)
    op.execute("""
        -- ── Estensioni ───────────────────────────────────────────────────────
        CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
        CREATE EXTENSION IF NOT EXISTS "pgcrypto";
    """)

    # ── ENUM types ────────────────────────────────────────────────────────────
    op.execute("CREATE TYPE user_role AS ENUM ('super_admin','admin','supervisor','operator','readonly')")
    op.execute("CREATE TYPE mailbox_status AS ENUM ('active','paused','error','deleted')")
    op.execute("CREATE TYPE pec_direction AS ENUM ('inbound','outbound')")
    op.execute("CREATE TYPE pec_state AS ENUM ('draft','queued','sent','accepted','delivered','anomaly','failed','received')")
    op.execute("CREATE TYPE pec_msg_type AS ENUM ('posta_certificata','accettazione','non_accettazione','presa_in_carico','avvenuta_consegna','mancata_consegna','errore_consegna','preavviso_mancata_consegna','rilevazione_virus','unknown')")
    op.execute("CREATE TYPE send_job_status AS ENUM ('pending','sending','sent','failed','retrying')")
    op.execute("CREATE TYPE archival_status AS ENUM ('pending','building_sip','uploading','uploaded','confirmed','rejected','failed')")

    # ── 1. TENANTS ────────────────────────────────────────────────────────────
    op.execute("""
        CREATE TABLE tenants (
            id              UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
            slug            VARCHAR(63)  NOT NULL UNIQUE,
            name            VARCHAR(255) NOT NULL,
            plan            VARCHAR(50)  NOT NULL DEFAULT 'starter',
            is_active       BOOLEAN      NOT NULL DEFAULT TRUE,
            max_mailboxes   INT          NOT NULL DEFAULT 5,
            max_users       INT          NOT NULL DEFAULT 10,
            created_at      TIMESTAMPTZ  NOT NULL DEFAULT NOW(),
            updated_at      TIMESTAMPTZ  NOT NULL DEFAULT NOW()
        )
    """)
    op.execute("CREATE INDEX idx_tenants_slug ON tenants (slug)")

    # ── 2. USERS ──────────────────────────────────────────────────────────────
    op.execute("""
        CREATE TABLE users (
            id                  UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
            tenant_id           UUID         NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
            email               VARCHAR(255) NOT NULL,
            password_hash       TEXT         NOT NULL,
            full_name           VARCHAR(255) NOT NULL,
            role                user_role    NOT NULL DEFAULT 'operator',
            is_active           BOOLEAN      NOT NULL DEFAULT TRUE,
            totp_secret         TEXT,
            totp_enabled        BOOLEAN      NOT NULL DEFAULT FALSE,
            last_login_at       TIMESTAMPTZ,
            failed_login_count  INT          NOT NULL DEFAULT 0,
            locked_until        TIMESTAMPTZ,
            created_at          TIMESTAMPTZ  NOT NULL DEFAULT NOW(),
            updated_at          TIMESTAMPTZ  NOT NULL DEFAULT NOW(),
            CONSTRAINT uq_user_email_tenant UNIQUE (tenant_id, email)
        )
    """)
    op.execute("CREATE INDEX idx_users_tenant ON users (tenant_id)")
    op.execute("CREATE INDEX idx_users_email ON users (email)")
    op.execute("ALTER TABLE users ENABLE ROW LEVEL SECURITY")
    op.execute("""
        CREATE POLICY users_tenant_isolation ON users
        USING (tenant_id = current_setting('app.current_tenant_id', TRUE)::UUID)
    """)

    # ── 3. REFRESH TOKENS ─────────────────────────────────────────────────────
    op.execute("""
        CREATE TABLE refresh_tokens (
            id          UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
            user_id     UUID        NOT NULL REFERENCES users(id) ON DELETE CASCADE,
            token_hash  TEXT        NOT NULL UNIQUE,
            issued_at   TIMESTAMPTZ NOT NULL DEFAULT NOW(),
            expires_at  TIMESTAMPTZ NOT NULL,
            revoked_at  TIMESTAMPTZ,
            user_agent  TEXT,
            ip_address  INET
        )
    """)
    op.execute("CREATE INDEX idx_rt_user ON refresh_tokens (user_id)")
    op.execute("CREATE INDEX idx_rt_expires ON refresh_tokens (expires_at) WHERE revoked_at IS NULL")

    # ── 4. MAILBOXES ──────────────────────────────────────────────────────────
    op.execute("""
        CREATE TABLE mailboxes (
            id                  UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
            tenant_id           UUID         NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
            email_address       VARCHAR(255) NOT NULL,
            display_name        VARCHAR(255),
            provider            VARCHAR(100),
            imap_host_enc       TEXT         NOT NULL,
            imap_port_enc       TEXT         NOT NULL,
            imap_user_enc       TEXT         NOT NULL,
            imap_pass_enc       TEXT         NOT NULL,
            imap_use_ssl        BOOLEAN      NOT NULL DEFAULT TRUE,
            smtp_host_enc       TEXT         NOT NULL,
            smtp_port_enc       TEXT         NOT NULL,
            smtp_user_enc       TEXT         NOT NULL,
            smtp_pass_enc       TEXT         NOT NULL,
            smtp_use_tls        BOOLEAN      NOT NULL DEFAULT TRUE,
            status              mailbox_status NOT NULL DEFAULT 'active',
            last_sync_at        TIMESTAMPTZ,
            last_sync_uid       BIGINT,
            sync_error_msg      TEXT,
            sync_error_count    INT          NOT NULL DEFAULT 0,
            created_by          UUID         REFERENCES users(id),
            created_at          TIMESTAMPTZ  NOT NULL DEFAULT NOW(),
            updated_at          TIMESTAMPTZ  NOT NULL DEFAULT NOW(),
            CONSTRAINT uq_mailbox_email_tenant UNIQUE (tenant_id, email_address)
        )
    """)
    op.execute("CREATE INDEX idx_mailboxes_tenant ON mailboxes (tenant_id)")
    op.execute("CREATE INDEX idx_mailboxes_status ON mailboxes (status) WHERE status = 'active'")
    op.execute("ALTER TABLE mailboxes ENABLE ROW LEVEL SECURITY")
    op.execute("""
        CREATE POLICY mailboxes_tenant_isolation ON mailboxes
        USING (tenant_id = current_setting('app.current_tenant_id', TRUE)::UUID)
    """)

    # ── 5. MESSAGES ───────────────────────────────────────────────────────────
    op.execute("""
        CREATE TABLE messages (
            id                  UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
            tenant_id           UUID          NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
            mailbox_id          UUID          NOT NULL REFERENCES mailboxes(id) ON DELETE CASCADE,
            message_id_header   TEXT,
            imap_uid            BIGINT,
            imap_folder         VARCHAR(255)  NOT NULL DEFAULT 'INBOX',
            direction           pec_direction NOT NULL,
            pec_type            pec_msg_type  NOT NULL DEFAULT 'posta_certificata',
            state               pec_state     NOT NULL,
            subject             TEXT,
            from_address        VARCHAR(255),
            to_addresses        TEXT[],
            cc_addresses        TEXT[],
            sent_at             TIMESTAMPTZ,
            received_at         TIMESTAMPTZ,
            size_bytes          BIGINT,
            body_text           TEXT,
            body_html           TEXT,
            has_attachments     BOOLEAN       NOT NULL DEFAULT FALSE,
            parent_message_id   UUID          REFERENCES messages(id),
            is_read             BOOLEAN       NOT NULL DEFAULT FALSE,
            is_starred          BOOLEAN       NOT NULL DEFAULT FALSE,
            is_archived         BOOLEAN       NOT NULL DEFAULT FALSE,
            archived_at         TIMESTAMPTZ,
            raw_eml_path        TEXT,
            created_at          TIMESTAMPTZ   NOT NULL DEFAULT NOW(),
            updated_at          TIMESTAMPTZ   NOT NULL DEFAULT NOW()
        )
    """)
    op.execute("CREATE INDEX idx_messages_tenant ON messages (tenant_id)")
    op.execute("CREATE INDEX idx_messages_mailbox ON messages (mailbox_id)")
    op.execute("CREATE INDEX idx_messages_state ON messages (state)")
    op.execute("CREATE INDEX idx_messages_received_at ON messages (received_at DESC)")
    op.execute("CREATE INDEX idx_messages_imap_uid ON messages (mailbox_id, imap_uid)")
    op.execute("CREATE INDEX idx_messages_parent ON messages (parent_message_id) WHERE parent_message_id IS NOT NULL")
    op.execute("CREATE INDEX idx_messages_subject_fts ON messages USING GIN (to_tsvector('italian', COALESCE(subject, '')))")
    op.execute("ALTER TABLE messages ENABLE ROW LEVEL SECURITY")
    op.execute("""
        CREATE POLICY messages_tenant_isolation ON messages
        USING (tenant_id = current_setting('app.current_tenant_id', TRUE)::UUID)
    """)

    # ── 6. ATTACHMENTS ────────────────────────────────────────────────────────
    op.execute("""
        CREATE TABLE attachments (
            id              UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
            tenant_id       UUID         NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
            message_id      UUID         NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
            filename        VARCHAR(512) NOT NULL,
            content_type    VARCHAR(255),
            size_bytes      BIGINT,
            storage_path    TEXT         NOT NULL,
            checksum_sha256 CHAR(64),
            created_at      TIMESTAMPTZ  NOT NULL DEFAULT NOW()
        )
    """)
    op.execute("CREATE INDEX idx_attachments_message ON attachments (message_id)")

    # ── 7. SEND_JOBS ──────────────────────────────────────────────────────────
    op.execute("""
        CREATE TABLE send_jobs (
            id              UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
            tenant_id       UUID              NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
            mailbox_id      UUID              NOT NULL REFERENCES mailboxes(id),
            message_id      UUID              REFERENCES messages(id),
            status          send_job_status   NOT NULL DEFAULT 'pending',
            attempt_count   INT               NOT NULL DEFAULT 0,
            max_attempts    INT               NOT NULL DEFAULT 5,
            next_retry_at   TIMESTAMPTZ,
            last_error      TEXT,
            queued_at       TIMESTAMPTZ       NOT NULL DEFAULT NOW(),
            sent_at         TIMESTAMPTZ,
            created_by      UUID              REFERENCES users(id)
        )
    """)
    op.execute("CREATE INDEX idx_sendjobs_tenant ON send_jobs (tenant_id)")
    op.execute("CREATE INDEX idx_sendjobs_status ON send_jobs (status, next_retry_at) WHERE status IN ('pending','retrying')")

    # ── 8. ARCHIVAL ───────────────────────────────────────────────────────────
    op.execute("""
        CREATE TABLE archival_batches (
            id                  UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
            tenant_id           UUID             NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
            conservatore_id     VARCHAR(100)     NOT NULL,
            status              archival_status  NOT NULL DEFAULT 'pending',
            sip_path            TEXT,
            sip_checksum        CHAR(64),
            versamento_id       TEXT,
            rdv_received_at     TIMESTAMPTZ,
            rdv_path            TEXT,
            rdv_checksum        CHAR(64),
            attempt_count       INT              NOT NULL DEFAULT 0,
            max_attempts        INT              NOT NULL DEFAULT 3,
            next_retry_at       TIMESTAMPTZ,
            last_error          TEXT,
            period_from         DATE             NOT NULL,
            period_to           DATE             NOT NULL,
            created_at          TIMESTAMPTZ      NOT NULL DEFAULT NOW(),
            updated_at          TIMESTAMPTZ      NOT NULL DEFAULT NOW()
        )
    """)
    op.execute("CREATE INDEX idx_archival_tenant ON archival_batches (tenant_id)")
    op.execute("CREATE INDEX idx_archival_status ON archival_batches (status, next_retry_at)")

    op.execute("""
        CREATE TABLE archival_batch_messages (
            batch_id    UUID NOT NULL REFERENCES archival_batches(id) ON DELETE CASCADE,
            message_id  UUID NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
            PRIMARY KEY (batch_id, message_id)
        )
    """)

    op.execute("""
        CREATE TABLE archival_dips (
            id              UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
            tenant_id       UUID         NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
            batch_id        UUID         REFERENCES archival_batches(id),
            requested_by    UUID         REFERENCES users(id),
            dip_path        TEXT,
            status          VARCHAR(50)  NOT NULL DEFAULT 'requested',
            requested_at    TIMESTAMPTZ  NOT NULL DEFAULT NOW(),
            received_at     TIMESTAMPTZ
        )
    """)

    # ── 9. AUDIT_LOG ──────────────────────────────────────────────────────────
    op.execute("""
        CREATE TABLE audit_log (
            id              BIGSERIAL    PRIMARY KEY,
            tenant_id       UUID         REFERENCES tenants(id),
            user_id         UUID         REFERENCES users(id),
            action          VARCHAR(100) NOT NULL,
            resource_type   VARCHAR(100),
            resource_id     UUID,
            ip_address      INET,
            user_agent      TEXT,
            payload         JSONB,
            outcome         VARCHAR(20)  NOT NULL DEFAULT 'success',
            occurred_at     TIMESTAMPTZ  NOT NULL DEFAULT NOW()
        )
    """)
    op.execute("CREATE INDEX idx_audit_tenant_date ON audit_log (tenant_id, occurred_at DESC)")
    op.execute("CREATE INDEX idx_audit_user ON audit_log (user_id, occurred_at DESC)")
    op.execute("CREATE INDEX idx_audit_action ON audit_log (action)")
    op.execute("ALTER TABLE audit_log ENABLE ROW LEVEL SECURITY")
    op.execute("CREATE POLICY audit_no_delete ON audit_log FOR DELETE USING (FALSE)")
    op.execute("CREATE POLICY audit_no_update ON audit_log FOR UPDATE USING (FALSE)")
    op.execute("""
        CREATE POLICY audit_tenant_read ON audit_log FOR SELECT
        USING (tenant_id = current_setting('app.current_tenant_id', TRUE)::UUID)
    """)

    # ── 10. LABELS ────────────────────────────────────────────────────────────
    op.execute("""
        CREATE TABLE labels (
            id          UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
            tenant_id   UUID         NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
            name        VARCHAR(100) NOT NULL,
            color       CHAR(7),
            CONSTRAINT uq_label_name_tenant UNIQUE (tenant_id, name)
        )
    """)

    op.execute("""
        CREATE TABLE message_labels (
            message_id  UUID NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
            label_id    UUID NOT NULL REFERENCES labels(id)   ON DELETE CASCADE,
            PRIMARY KEY (message_id, label_id)
        )
    """)

    # ── 11. MAILBOX_PERMISSIONS (Fase 1-A) ────────────────────────────────────
    op.execute("""
        CREATE TABLE mailbox_permissions (
            id          UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
            tenant_id   UUID    NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
            user_id     UUID    NOT NULL REFERENCES users(id)   ON DELETE CASCADE,
            mailbox_id  UUID    NOT NULL REFERENCES mailboxes(id) ON DELETE CASCADE,
            can_read    BOOLEAN NOT NULL DEFAULT TRUE,
            can_send    BOOLEAN NOT NULL DEFAULT FALSE,
            can_manage  BOOLEAN NOT NULL DEFAULT FALSE,
            granted_by  UUID    REFERENCES users(id),
            granted_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
            CONSTRAINT uq_perm_user_mailbox UNIQUE (user_id, mailbox_id)
        )
    """)
    op.execute("CREATE INDEX idx_mbperm_user ON mailbox_permissions (user_id)")
    op.execute("CREATE INDEX idx_mbperm_mailbox ON mailbox_permissions (mailbox_id)")
    op.execute("CREATE INDEX idx_mbperm_tenant ON mailbox_permissions (tenant_id)")

    # ── Trigger updated_at ────────────────────────────────────────────────────
    op.execute("""
        CREATE OR REPLACE FUNCTION set_updated_at()
        RETURNS TRIGGER LANGUAGE plpgsql AS $$
        BEGIN NEW.updated_at = NOW(); RETURN NEW; END;
        $$
    """)
    for table in ["tenants", "users", "mailboxes", "messages", "archival_batches"]:
        op.execute(f"""
            CREATE TRIGGER trg_{table}_updated_at
            BEFORE UPDATE ON {table}
            FOR EACH ROW EXECUTE FUNCTION set_updated_at()
        """)


def downgrade() -> None:
    # Rimuovi trigger
    for table in ["tenants", "users", "mailboxes", "messages", "archival_batches"]:
        op.execute(f"DROP TRIGGER IF EXISTS trg_{table}_updated_at ON {table}")
    op.execute("DROP FUNCTION IF EXISTS set_updated_at()")

    # Rimuovi tabelle (ordine inverso per FK)
    for table in [
        "mailbox_permissions", "message_labels", "labels",
        "audit_log", "archival_dips", "archival_batch_messages",
        "archival_batches", "send_jobs", "attachments", "messages",
        "mailboxes", "refresh_tokens", "users", "tenants",
    ]:
        op.execute(f"DROP TABLE IF EXISTS {table} CASCADE")

    # Rimuovi enum types
    for enum_name in [
        "archival_status", "send_job_status", "pec_msg_type",
        "pec_state", "pec_direction", "mailbox_status", "user_role",
    ]:
        op.execute(f"DROP TYPE IF EXISTS {enum_name}")
