-- ============================================================================
-- Audit Logs Migration
-- Add audit logging table to track user actions and system changes
-- ============================================================================

-- ============================================================================
-- ENUM TYPE: audit_action
-- ============================================================================
CREATE TYPE audit_action AS ENUM (
    'CREATE',
    'UPDATE',
    'DELETE',
    'LOGIN',
    'LOGOUT',
    'READ',
    'EXPORT',
    'BULK_UPLOAD',
    'STATUS_CHANGE',
    'PERMISSION_CHANGE'
);

-- ============================================================================
-- TABLE: audit_logs
-- ============================================================================
CREATE TABLE audit_logs (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    
    -- User information
    user_id UUID REFERENCES users(id) ON DELETE SET NULL,
    user_email VARCHAR(255) NOT NULL,
    user_name VARCHAR(255) NOT NULL,
    
    -- Action details
    action audit_action NOT NULL,
    table_name VARCHAR(100) NOT NULL,
    record_id UUID,
    
    -- Change tracking
    old_values JSONB,
    new_values JSONB,
    description TEXT,
    
    -- Request metadata
    ip_address INET,
    user_agent TEXT,
    
    -- Status
    success BOOLEAN NOT NULL DEFAULT TRUE,
    error_message TEXT,
    
    -- Timestamp
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);

-- ============================================================================
-- INDEXES
-- ============================================================================
CREATE INDEX idx_audit_logs_user_id ON audit_logs(user_id);
CREATE INDEX idx_audit_logs_action ON audit_logs(action);
CREATE INDEX idx_audit_logs_table_name ON audit_logs(table_name);
CREATE INDEX idx_audit_logs_record_id ON audit_logs(record_id);
CREATE INDEX idx_audit_logs_created_at ON audit_logs(created_at DESC);
CREATE INDEX idx_audit_logs_user_id_created_at ON audit_logs(user_id, created_at DESC);
CREATE INDEX idx_audit_logs_table_name_record_id ON audit_logs(table_name, record_id);

-- Index for JSON queries on old_values and new_values
CREATE INDEX idx_audit_logs_old_values ON audit_logs USING GIN (old_values);
CREATE INDEX idx_audit_logs_new_values ON audit_logs USING GIN (new_values);

-- ============================================================================
-- COMMENTS
-- ============================================================================
COMMENT ON TABLE audit_logs IS 'System audit log tracking all user actions and data changes';
COMMENT ON COLUMN audit_logs.user_id IS 'Reference to user who performed the action (nullable if user deleted)';
COMMENT ON COLUMN audit_logs.user_email IS 'Email snapshot at time of action';
COMMENT ON COLUMN audit_logs.user_name IS 'Name snapshot at time of action';
COMMENT ON COLUMN audit_logs.action IS 'Type of action performed';
COMMENT ON COLUMN audit_logs.table_name IS 'Database table affected by the action';
COMMENT ON COLUMN audit_logs.record_id IS 'ID of the specific record affected';
COMMENT ON COLUMN audit_logs.old_values IS 'JSON snapshot of values before change';
COMMENT ON COLUMN audit_logs.new_values IS 'JSON snapshot of values after change';
COMMENT ON COLUMN audit_logs.description IS 'Human-readable description of the action';
COMMENT ON COLUMN audit_logs.ip_address IS 'IP address of the user';
COMMENT ON COLUMN audit_logs.user_agent IS 'Browser/client user agent string';
COMMENT ON COLUMN audit_logs.success IS 'Whether the action completed successfully';
COMMENT ON COLUMN audit_logs.error_message IS 'Error message if action failed';

-- ============================================================================
-- HELPER FUNCTION: Get current user info from request context
-- ============================================================================
CREATE OR REPLACE FUNCTION get_current_user_info()
RETURNS TABLE (
    user_id UUID,
    user_email VARCHAR(255),
    user_name VARCHAR(255)
) AS $$
BEGIN
    -- This will be called from application code with current_setting
    RETURN QUERY
    SELECT 
        NULLIF(current_setting('app.current_user_id', true), '')::UUID,
        NULLIF(current_setting('app.current_user_email', true), ''),
        NULLIF(current_setting('app.current_user_name', true), '');
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- ============================================================================
-- HELPER FUNCTION: Log audit entry
-- ============================================================================
CREATE OR REPLACE FUNCTION log_audit(
    p_user_id UUID,
    p_user_email VARCHAR(255),
    p_user_name VARCHAR(255),
    p_action audit_action,
    p_table_name VARCHAR(100),
    p_record_id UUID DEFAULT NULL,
    p_old_values JSONB DEFAULT NULL,
    p_new_values JSONB DEFAULT NULL,
    p_description TEXT DEFAULT NULL,
    p_ip_address INET DEFAULT NULL,
    p_user_agent TEXT DEFAULT NULL,
    p_success BOOLEAN DEFAULT TRUE,
    p_error_message TEXT DEFAULT NULL
)
RETURNS UUID AS $$
DECLARE
    v_log_id UUID;
BEGIN
    INSERT INTO audit_logs (
        user_id,
        user_email,
        user_name,
        action,
        table_name,
        record_id,
        old_values,
        new_values,
        description,
        ip_address,
        user_agent,
        success,
        error_message
    ) VALUES (
        p_user_id,
        p_user_email,
        p_user_name,
        p_action,
        p_table_name,
        p_record_id,
        p_old_values,
        p_new_values,
        p_description,
        p_ip_address,
        p_user_agent,
        p_success,
        p_error_message
    ) RETURNING id INTO v_log_id;
    
    RETURN v_log_id;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- ============================================================================
-- VIEW: audit_logs_summary
-- ============================================================================
CREATE OR REPLACE VIEW audit_logs_summary AS
SELECT 
    al.id,
    al.user_email,
    al.user_name,
    al.action,
    al.table_name,
    al.record_id,
    al.description,
    al.success,
    al.created_at,
    al.ip_address,
    -- User reference (may be null if user deleted)
    u.id AS current_user_id,
    u.is_active AS user_is_active
FROM audit_logs al
LEFT JOIN users u ON al.user_id = u.id
ORDER BY al.created_at DESC;

COMMENT ON VIEW audit_logs_summary IS 'Audit logs with user status information';

-- ============================================================================
-- VIEW: audit_statistics
-- ============================================================================
CREATE OR REPLACE VIEW audit_statistics AS
SELECT 
    DATE(created_at) AS date,
    action,
    table_name,
    COUNT(*) AS action_count,
    COUNT(DISTINCT user_id) AS unique_users,
    SUM(CASE WHEN success THEN 1 ELSE 0 END) AS successful_actions,
    SUM(CASE WHEN NOT success THEN 1 ELSE 0 END) AS failed_actions
FROM audit_logs
GROUP BY DATE(created_at), action, table_name
ORDER BY date DESC, action_count DESC;

COMMENT ON VIEW audit_statistics IS 'Daily statistics of audit log actions';

-- ============================================================================
-- END OF MIGRATION
-- ============================================================================
