-- ============================================================================
-- E2EE Session Manager Tables
-- ============================================================================
-- Tables to support the E2EE session management edge function
-- These tables handle session commands, events, and cleanup operations
-- ============================================================================

-- ============================================================================
-- 1. Session Commands Table
-- ============================================================================

-- Table to store session management commands
CREATE TABLE IF NOT EXISTS e2ee_session_commands (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    -- Command details
    user_id UUID NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
    recipient_id UUID REFERENCES profiles(id) ON DELETE CASCADE,
    conversation_id UUID REFERENCES encrypted_conversations(id) ON DELETE CASCADE,
    command_type TEXT NOT NULL CHECK (command_type IN ('session_reset', 'conversation_cleanup', 'key_refresh')),
    status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'completed', 'failed')),

    -- Metadata
    created_at TIMESTAMPTZ DEFAULT NOW(),
    completed_at TIMESTAMPTZ,
    error_message TEXT
);

-- Indexes for efficient command processing
CREATE INDEX IF NOT EXISTS idx_session_commands_user ON e2ee_session_commands(user_id);
CREATE INDEX IF NOT EXISTS idx_session_commands_status ON e2ee_session_commands(status);
CREATE INDEX IF NOT EXISTS idx_session_commands_type ON e2ee_session_commands(command_type);
CREATE INDEX IF NOT EXISTS idx_session_commands_conversation ON e2ee_session_commands(conversation_id);

-- ============================================================================
-- 2. Session Events Table
-- ============================================================================

-- Table to store session management events for realtime notifications
CREATE TABLE IF NOT EXISTS e2ee_session_events (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    -- Event details
    user_id UUID NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
    event_type TEXT NOT NULL CHECK (event_type IN ('session_reset', 'conversation_cleanup', 'key_refresh', 'decryption_failure')),
    recipient_id UUID REFERENCES profiles(id) ON DELETE CASCADE,
    conversation_id UUID REFERENCES encrypted_conversations(id) ON DELETE CASCADE,

    -- Additional context
    message_id UUID REFERENCES encrypted_messages(id) ON DELETE CASCADE,
    error_details JSONB,

    -- Metadata
    timestamp TIMESTAMPTZ DEFAULT NOW(),
    processed_at TIMESTAMPTZ,
    processed_by TEXT
);

-- Indexes for efficient event processing
CREATE INDEX IF NOT EXISTS idx_session_events_user ON e2ee_session_events(user_id);
CREATE INDEX IF NOT EXISTS idx_session_events_type ON e2ee_session_events(event_type);
CREATE INDEX IF NOT EXISTS idx_session_events_timestamp ON e2ee_session_events(timestamp DESC);

-- ============================================================================
-- 3. Decryption Failure Logs
-- ============================================================================

-- Table to log decryption failures for debugging and recovery
CREATE TABLE IF NOT EXISTS e2ee_decryption_failures (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    -- Failure details
    message_id UUID NOT NULL REFERENCES encrypted_messages(id) ON DELETE CASCADE,
    sender_id UUID NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
    recipient_id UUID NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
    conversation_id UUID NOT NULL REFERENCES encrypted_conversations(id) ON DELETE CASCADE,

    -- Error information
    error_type TEXT NOT NULL,
    error_message TEXT,
    stack_trace TEXT,
    ciphertext_length INTEGER,
    message_type INTEGER,

    -- Context for debugging
    session_key_exists BOOLEAN,
    ephemeral_key_in_header BOOLEAN,
    header_data JSONB,

    -- Recovery status
    recovery_attempted BOOLEAN DEFAULT FALSE,
    recovery_success BOOLEAN,
    recovery_method TEXT,

    -- Metadata
    created_at TIMESTAMPTZ DEFAULT NOW(),
    last_updated TIMESTAMPTZ DEFAULT NOW()
);

-- Indexes for failure analysis
CREATE INDEX IF NOT EXISTS idx_decryption_failures_message ON e2ee_decryption_failures(message_id);
CREATE INDEX IF NOT EXISTS idx_decryption_failures_conversation ON e2ee_decryption_failures(conversation_id);
CREATE INDEX IF NOT EXISTS idx_decryption_failures_recipient ON e2ee_decryption_failures(recipient_id);
CREATE INDEX IF NOT EXISTS idx_decryption_failures_timestamp ON e2ee_decryption_failures(created_at DESC);

-- ============================================================================
-- 4. RLS Policies
-- ============================================================================

-- Enable RLS on all new tables
ALTER TABLE e2ee_session_commands ENABLE ROW LEVEL SECURITY;
ALTER TABLE e2ee_session_events ENABLE ROW LEVEL SECURITY;
ALTER TABLE e2ee_decryption_failures ENABLE ROW LEVEL SECURITY;

-- Session Commands: Users can only see their own commands
CREATE POLICY session_commands_select_own ON e2ee_session_commands
    FOR SELECT USING (auth.uid() = user_id);

CREATE POLICY session_commands_insert_own ON e2ee_session_commands
    FOR INSERT WITH CHECK (auth.uid() = user_id);

CREATE POLICY session_commands_update_own ON e2ee_session_commands
    FOR UPDATE USING (auth.uid() = user_id);

-- Session Events: Users can only see their own events
CREATE POLICY session_events_select_own ON e2ee_session_events
    FOR SELECT USING (auth.uid() = user_id);

CREATE POLICY session_events_insert_own ON e2ee_session_events
    FOR INSERT WITH CHECK (auth.uid() = user_id);

CREATE POLICY session_events_update_own ON e2ee_session_events
    FOR UPDATE USING (auth.uid() = user_id);

-- Decryption Failures: Users can only see failures for their own messages
CREATE POLICY decryption_failures_select_own ON e2ee_decryption_failures
    FOR SELECT USING (auth.uid() = recipient_id);

CREATE POLICY decryption_failures_insert_own ON e2ee_decryption_failures
    FOR INSERT WITH CHECK (auth.uid() = recipient_id);

CREATE POLICY decryption_failures_update_own ON e2ee_decryption_failures
    FOR UPDATE USING (auth.uid() = recipient_id);

-- ============================================================================
-- 5. Realtime Subscriptions
-- ============================================================================

-- Enable realtime for session events
ALTER PUBLICATION supabase_realtime ADD TABLE e2ee_session_events;
ALTER PUBLICATION supabase_realtime ADD TABLE e2ee_session_commands;

-- ============================================================================
-- 6. Comments for Documentation
-- ============================================================================

COMMENT ON TABLE e2ee_session_commands IS 'Commands for E2EE session management (reset, cleanup, key refresh). Processed by client and edge functions.';
COMMENT ON TABLE e2ee_session_events IS 'Realtime events for E2EE session management. Triggers client-side actions.';
COMMENT ON TABLE e2ee_decryption_failures IS 'Logs of decryption failures for debugging and automatic recovery.';
COMMENT ON COLUMN e2ee_decryption_failures.error_type IS 'Type of decryption error (e.g., "mac_failure", "session_mismatch")';
COMMENT ON COLUMN e2ee_decryption_failures.recovery_method IS 'Method used for recovery (e.g., "session_reset", "key_refresh")';

-- ============================================================================
-- 7. Helper Functions
-- ============================================================================

-- Function to log decryption failures
CREATE OR REPLACE FUNCTION log_decryption_failure(
    p_message_id UUID,
    p_sender_id UUID,
    p_recipient_id UUID,
    p_conversation_id UUID,
    p_error_type TEXT,
    p_error_message TEXT,
    p_stack_trace TEXT,
    p_ciphertext_length INTEGER,
    p_message_type INTEGER,
    p_session_key_exists BOOLEAN,
    p_ephemeral_key_in_header BOOLEAN,
    p_header_data JSONB
) RETURNS VOID AS $$
BEGIN
    INSERT INTO e2ee_decryption_failures (
        message_id, sender_id, recipient_id, conversation_id,
        error_type, error_message, stack_trace, ciphertext_length, message_type,
        session_key_exists, ephemeral_key_in_header, header_data
    ) VALUES (
        p_message_id, p_sender_id, p_recipient_id, p_conversation_id,
        p_error_type, p_error_message, p_stack_trace, p_ciphertext_length, p_message_type,
        p_session_key_exists, p_ephemeral_key_in_header, p_header_data
    );
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- Function to mark recovery attempts
CREATE OR REPLACE FUNCTION mark_recovery_attempt(
    p_failure_id UUID,
    p_recovery_method TEXT,
    p_success BOOLEAN
) RETURNS VOID AS $$
BEGIN
    UPDATE e2ee_decryption_failures
    SET
        recovery_attempted = TRUE,
        recovery_success = p_success,
        recovery_method = p_recovery_method,
        last_updated = NOW()
    WHERE id = p_failure_id;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- ============================================================================
-- 8. Cleanup Function
-- ============================================================================

-- Function to cleanup old session data
CREATE OR REPLACE FUNCTION cleanup_old_e2ee_data()
RETURNS VOID AS $$
BEGIN
    -- Delete old commands (older than 30 days)
    DELETE FROM e2ee_session_commands
    WHERE created_at < NOW() - INTERVAL '30 days';

    -- Delete old events (older than 7 days)
    DELETE FROM e2ee_session_events
    WHERE timestamp < NOW() - INTERVAL '7 days';

    -- Delete old failure logs (older than 90 days)
    DELETE FROM e2ee_decryption_failures
    WHERE created_at < NOW() - INTERVAL '90 days';
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
