-- 021_archived_audit_events.sql
-- Archived Transaction Audit Events Table
-- SOX/MiFID II Compliance - Long-term Audit Storage
-- Created: 2025-10-03 (Wave 82 Agent 3)

-- Enable required extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- Archived audit events table (mirrors transaction_audit_events structure)
-- Used for long-term storage after retention period cleanup
CREATE TABLE archived_audit_events (
    -- Primary identification
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    event_id VARCHAR(255) NOT NULL,

    -- Event classification
    event_type VARCHAR(50) NOT NULL,

    -- High-precision timestamps
    timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
    timestamp_nanos BIGINT NOT NULL,

    -- Transaction context
    transaction_id VARCHAR(255) NOT NULL,
    order_id VARCHAR(255) NOT NULL,

    -- Actor identification (user/system)
    actor VARCHAR(255) NOT NULL,
    session_id VARCHAR(255),
    client_ip VARCHAR(45), -- IPv4 or IPv6

    -- Event details (JSONB for flexibility)
    details JSONB NOT NULL,

    -- State tracking for modifications
    before_state JSONB,
    after_state JSONB,

    -- Compliance metadata
    compliance_tags TEXT[] NOT NULL DEFAULT '{}',
    risk_level VARCHAR(20) NOT NULL,

    -- Security and integrity
    digital_signature VARCHAR(512),
    checksum VARCHAR(64) NOT NULL,

    -- Original creation time
    created_at TIMESTAMP WITH TIME ZONE NOT NULL,

    -- Archival metadata
    archived_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    archived_by VARCHAR(255) DEFAULT 'system',

    -- Constraints for data integrity
    CONSTRAINT valid_archived_event_id CHECK (length(event_id) > 0),
    CONSTRAINT valid_archived_transaction_id CHECK (length(transaction_id) > 0),
    CONSTRAINT valid_archived_order_id CHECK (length(order_id) > 0),
    CONSTRAINT valid_archived_actor CHECK (length(actor) > 0),
    CONSTRAINT valid_archived_checksum CHECK (length(checksum) = 64),
    CONSTRAINT valid_archived_risk_level CHECK (risk_level IN ('Low', 'Medium', 'High', 'Critical')),
    CONSTRAINT positive_archived_timestamp_nanos CHECK (timestamp_nanos >= 0)
);

-- Performance indexes for archived data queries
CREATE INDEX idx_archived_audit_events_timestamp ON archived_audit_events(timestamp DESC);
CREATE INDEX idx_archived_audit_events_transaction_id ON archived_audit_events(transaction_id);
CREATE INDEX idx_archived_audit_events_order_id ON archived_audit_events(order_id);
CREATE INDEX idx_archived_audit_events_actor ON archived_audit_events(actor);
CREATE INDEX idx_archived_audit_events_event_type ON archived_audit_events(event_type);
CREATE INDEX idx_archived_audit_events_archived_at ON archived_audit_events(archived_at DESC);

-- GIN index for compliance tags
CREATE INDEX idx_archived_audit_events_compliance_tags ON archived_audit_events USING GIN(compliance_tags);

-- BRIN index for time-series optimization
CREATE INDEX idx_archived_audit_events_timestamp_brin ON archived_audit_events USING BRIN(timestamp);

-- Table partitioning by archive date (monthly partitions for long-term storage)
-- Note: Implement partitioning strategy based on archive retention requirements

-- Row Level Security for archived data
ALTER TABLE archived_audit_events ENABLE ROW LEVEL SECURITY;

-- RLS Policy: Read-only access for compliance/admin roles
CREATE POLICY archived_audit_events_read_policy ON archived_audit_events
    FOR SELECT
    USING (
        has_role('admin')
        OR has_role('compliance_officer')
        OR has_role('risk_manager')
        OR has_role('auditor')
    );

-- RLS Policy: Only system can INSERT archived events
CREATE POLICY archived_audit_events_insert_policy ON archived_audit_events
    FOR INSERT
    WITH CHECK (has_role('admin') OR has_role('system'));

-- NO UPDATE/DELETE allowed (immutable archive)
REVOKE UPDATE, DELETE ON archived_audit_events FROM PUBLIC;
REVOKE UPDATE, DELETE ON archived_audit_events FROM authenticated_users;

-- Grant permissions
GRANT SELECT ON archived_audit_events TO authenticated_users;
GRANT INSERT ON archived_audit_events TO authenticated_users;

-- Function to archive expired audit events
CREATE OR REPLACE FUNCTION archive_expired_audit_events(
    p_retention_days INTEGER DEFAULT 2555
)
RETURNS TABLE (
    archived_count BIGINT,
    deleted_count BIGINT
) AS $$
DECLARE
    v_cutoff_date TIMESTAMP WITH TIME ZONE;
    v_archived BIGINT;
    v_deleted BIGINT;
BEGIN
    -- Calculate cutoff date (default 7 years for SOX compliance)
    v_cutoff_date := NOW() - (p_retention_days || ' days')::INTERVAL;

    -- Archive events to archived_audit_events table (atomic transaction)
    WITH archived AS (
        INSERT INTO archived_audit_events (
            event_id, event_type, timestamp, timestamp_nanos,
            transaction_id, order_id, actor, session_id, client_ip,
            details, before_state, after_state,
            compliance_tags, risk_level, digital_signature, checksum,
            created_at, archived_at, archived_by
        )
        SELECT
            event_id, event_type, timestamp, timestamp_nanos,
            transaction_id, order_id, actor, session_id, client_ip,
            details, before_state, after_state,
            compliance_tags, risk_level, digital_signature, checksum,
            created_at, NOW(), 'system'
        FROM transaction_audit_events
        WHERE timestamp < v_cutoff_date
        RETURNING 1
    )
    SELECT COUNT(*) INTO v_archived FROM archived;

    -- Delete only after successful archive
    WITH deleted AS (
        DELETE FROM transaction_audit_events
        WHERE timestamp < v_cutoff_date
        RETURNING 1
    )
    SELECT COUNT(*) INTO v_deleted FROM deleted;

    RETURN QUERY SELECT v_archived, v_deleted;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- Function to query archived audit events
CREATE OR REPLACE FUNCTION query_archived_audit_events(
    p_start_time TIMESTAMP WITH TIME ZONE,
    p_end_time TIMESTAMP WITH TIME ZONE,
    p_transaction_id VARCHAR DEFAULT NULL,
    p_order_id VARCHAR DEFAULT NULL,
    p_limit INTEGER DEFAULT 1000,
    p_offset INTEGER DEFAULT 0
)
RETURNS TABLE (
    event_id VARCHAR,
    event_type VARCHAR,
    timestamp TIMESTAMP WITH TIME ZONE,
    transaction_id VARCHAR,
    order_id VARCHAR,
    actor VARCHAR,
    details JSONB,
    risk_level VARCHAR,
    archived_at TIMESTAMP WITH TIME ZONE
) AS $$
BEGIN
    RETURN QUERY
    SELECT
        e.event_id,
        e.event_type,
        e.timestamp,
        e.transaction_id,
        e.order_id,
        e.actor,
        e.details,
        e.risk_level,
        e.archived_at
    FROM archived_audit_events e
    WHERE e.timestamp >= p_start_time
      AND e.timestamp <= p_end_time
      AND (p_transaction_id IS NULL OR e.transaction_id = p_transaction_id)
      AND (p_order_id IS NULL OR e.order_id = p_order_id)
    ORDER BY e.timestamp DESC
    LIMIT p_limit
    OFFSET p_offset;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- Grant execute permissions on functions
GRANT EXECUTE ON FUNCTION archive_expired_audit_events TO authenticated_users;
GRANT EXECUTE ON FUNCTION query_archived_audit_events TO authenticated_users;

-- Comments for documentation
COMMENT ON TABLE archived_audit_events IS
    'Long-term archive for audit trails after retention period. SOX/MiFID II compliant. Immutable - no updates/deletes allowed.';

COMMENT ON COLUMN archived_audit_events.archived_at IS
    'Timestamp when this event was archived from the active audit trail';

COMMENT ON FUNCTION archive_expired_audit_events IS
    'Archives audit events older than retention period and deletes from active table. Uses transaction for atomicity.';

COMMENT ON FUNCTION query_archived_audit_events IS
    'Query archived audit events with flexible filtering and pagination';

-- Performance optimization: Analyze table for query planner
ANALYZE archived_audit_events;
