-- ============================================
-- Migration: V20260120_003
-- Description: Migrate audit.audit_logs structure
-- Changes:
--   - Rename entity_type -> resource_type
--   - Rename entity_id -> resource_id
--   - Add user_email, actor_type columns
--   - Add resource_name, severity columns
--   - Add request_id, session_id columns
--   - Add endpoint, http_method, response_status, duration_ms columns
--   - Change changes JSONB -> old_values, new_values, changed_fields
-- ============================================

-- UP Migration
BEGIN;

-- ============================================
-- 1. Ensure severity ENUM exists
-- ============================================

DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM pg_type
        WHERE typname = 'severity'
        AND typnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'audit')
    ) THEN
        CREATE TYPE audit.severity AS ENUM ('info', 'warning', 'error', 'critical');
        RAISE NOTICE 'Created audit.severity enum';
    END IF;
END $$;

-- ============================================
-- 2. Rename entity_type -> resource_type (if legacy)
-- ============================================

DO $$
BEGIN
    IF EXISTS (
        SELECT 1 FROM information_schema.columns
        WHERE table_schema = 'audit' AND table_name = 'audit_logs' AND column_name = 'entity_type'
    ) THEN
        -- Drop old index if exists
        DROP INDEX IF EXISTS audit.idx_audit_logs_entity;

        -- Rename column
        ALTER TABLE audit.audit_logs RENAME COLUMN entity_type TO resource_type;

        -- Update column type if needed
        ALTER TABLE audit.audit_logs ALTER COLUMN resource_type TYPE VARCHAR(100);

        RAISE NOTICE 'Renamed entity_type to resource_type';
    END IF;
END $$;

-- ============================================
-- 3. Rename entity_id -> resource_id (if legacy)
-- ============================================

DO $$
BEGIN
    IF EXISTS (
        SELECT 1 FROM information_schema.columns
        WHERE table_schema = 'audit' AND table_name = 'audit_logs' AND column_name = 'entity_id'
    ) THEN
        ALTER TABLE audit.audit_logs RENAME COLUMN entity_id TO resource_id;
        ALTER TABLE audit.audit_logs ALTER COLUMN resource_id TYPE VARCHAR(255);
        RAISE NOTICE 'Renamed entity_id to resource_id';
    END IF;
END $$;

-- ============================================
-- 4. Add actor columns
-- ============================================

-- user_email
DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM information_schema.columns
        WHERE table_schema = 'audit' AND table_name = 'audit_logs' AND column_name = 'user_email'
    ) THEN
        ALTER TABLE audit.audit_logs ADD COLUMN user_email VARCHAR(255);

        -- Backfill user_email from users table
        UPDATE audit.audit_logs al
        SET user_email = u.email
        FROM users.users u
        WHERE al.user_id = u.id
        AND al.user_email IS NULL;

        RAISE NOTICE 'Added user_email column and backfilled from users table';
    END IF;
END $$;

-- actor_type
DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM information_schema.columns
        WHERE table_schema = 'audit' AND table_name = 'audit_logs' AND column_name = 'actor_type'
    ) THEN
        ALTER TABLE audit.audit_logs ADD COLUMN actor_type VARCHAR(50) DEFAULT 'user';
        RAISE NOTICE 'Added actor_type column';
    END IF;
END $$;

-- ============================================
-- 5. Add resource_name column
-- ============================================

DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM information_schema.columns
        WHERE table_schema = 'audit' AND table_name = 'audit_logs' AND column_name = 'resource_name'
    ) THEN
        ALTER TABLE audit.audit_logs ADD COLUMN resource_name VARCHAR(255);
        RAISE NOTICE 'Added resource_name column';
    END IF;
END $$;

-- ============================================
-- 6. Add severity column
-- ============================================

DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM information_schema.columns
        WHERE table_schema = 'audit' AND table_name = 'audit_logs' AND column_name = 'severity'
    ) THEN
        ALTER TABLE audit.audit_logs ADD COLUMN severity audit.severity DEFAULT 'info';

        -- Create index for severity filtering
        CREATE INDEX idx_audit_logs_severity ON audit.audit_logs(tenant_id, severity)
            WHERE severity IN ('warning', 'error', 'critical');

        RAISE NOTICE 'Added severity column';
    END IF;
END $$;

-- ============================================
-- 7. Add context columns
-- ============================================

-- request_id
DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM information_schema.columns
        WHERE table_schema = 'audit' AND table_name = 'audit_logs' AND column_name = 'request_id'
    ) THEN
        ALTER TABLE audit.audit_logs ADD COLUMN request_id VARCHAR(100);
        RAISE NOTICE 'Added request_id column';
    END IF;
END $$;

-- session_id
DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM information_schema.columns
        WHERE table_schema = 'audit' AND table_name = 'audit_logs' AND column_name = 'session_id'
    ) THEN
        ALTER TABLE audit.audit_logs ADD COLUMN session_id UUID;
        RAISE NOTICE 'Added session_id column';
    END IF;
END $$;

-- ============================================
-- 8. Add HTTP context columns
-- ============================================

-- endpoint
DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM information_schema.columns
        WHERE table_schema = 'audit' AND table_name = 'audit_logs' AND column_name = 'endpoint'
    ) THEN
        ALTER TABLE audit.audit_logs ADD COLUMN endpoint VARCHAR(255);
        RAISE NOTICE 'Added endpoint column';
    END IF;
END $$;

-- http_method
DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM information_schema.columns
        WHERE table_schema = 'audit' AND table_name = 'audit_logs' AND column_name = 'http_method'
    ) THEN
        ALTER TABLE audit.audit_logs ADD COLUMN http_method VARCHAR(10);
        RAISE NOTICE 'Added http_method column';
    END IF;
END $$;

-- response_status
DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM information_schema.columns
        WHERE table_schema = 'audit' AND table_name = 'audit_logs' AND column_name = 'response_status'
    ) THEN
        ALTER TABLE audit.audit_logs ADD COLUMN response_status SMALLINT;
        RAISE NOTICE 'Added response_status column';
    END IF;
END $$;

-- duration_ms
DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM information_schema.columns
        WHERE table_schema = 'audit' AND table_name = 'audit_logs' AND column_name = 'duration_ms'
    ) THEN
        ALTER TABLE audit.audit_logs ADD COLUMN duration_ms INTEGER;
        RAISE NOTICE 'Added duration_ms column';
    END IF;
END $$;

-- ============================================
-- 9. Migrate changes JSONB -> old_values, new_values, changed_fields
-- ============================================

-- old_values
DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM information_schema.columns
        WHERE table_schema = 'audit' AND table_name = 'audit_logs' AND column_name = 'old_values'
    ) THEN
        ALTER TABLE audit.audit_logs ADD COLUMN old_values JSONB;
        RAISE NOTICE 'Added old_values column';
    END IF;
END $$;

-- new_values
DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM information_schema.columns
        WHERE table_schema = 'audit' AND table_name = 'audit_logs' AND column_name = 'new_values'
    ) THEN
        ALTER TABLE audit.audit_logs ADD COLUMN new_values JSONB;
        RAISE NOTICE 'Added new_values column';
    END IF;
END $$;

-- changed_fields
DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM information_schema.columns
        WHERE table_schema = 'audit' AND table_name = 'audit_logs' AND column_name = 'changed_fields'
    ) THEN
        ALTER TABLE audit.audit_logs ADD COLUMN changed_fields JSONB;
        RAISE NOTICE 'Added changed_fields column';
    END IF;
END $$;

-- Migrate data from 'changes' column if it exists
DO $$
BEGIN
    IF EXISTS (
        SELECT 1 FROM information_schema.columns
        WHERE table_schema = 'audit' AND table_name = 'audit_logs' AND column_name = 'changes'
    ) THEN
        -- Extract old_values from changes
        UPDATE audit.audit_logs
        SET old_values = changes->'old'
        WHERE changes IS NOT NULL
        AND changes ? 'old'
        AND old_values IS NULL;

        -- Extract new_values from changes
        UPDATE audit.audit_logs
        SET new_values = changes->'new'
        WHERE changes IS NOT NULL
        AND changes ? 'new'
        AND new_values IS NULL;

        -- Extract changed_fields from changes
        UPDATE audit.audit_logs
        SET changed_fields = changes->'fields'
        WHERE changes IS NOT NULL
        AND changes ? 'fields'
        AND changed_fields IS NULL;

        -- Alternative: if changes is flat diff, create changed_fields from keys
        UPDATE audit.audit_logs
        SET changed_fields = (
            SELECT jsonb_agg(key)
            FROM jsonb_object_keys(changes) AS key
            WHERE key NOT IN ('old', 'new', 'fields')
        )
        WHERE changes IS NOT NULL
        AND NOT (changes ? 'old')
        AND NOT (changes ? 'new')
        AND changed_fields IS NULL;

        -- Drop old column after migration
        ALTER TABLE audit.audit_logs DROP COLUMN changes;

        RAISE NOTICE 'Migrated changes column to old_values, new_values, changed_fields';
    END IF;
END $$;

-- ============================================
-- 10. Update/create indexes for new structure
-- ============================================

-- Index for resource queries
DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM pg_indexes
        WHERE schemaname = 'audit' AND indexname = 'idx_audit_logs_resource'
    ) THEN
        CREATE INDEX idx_audit_logs_resource ON audit.audit_logs(tenant_id, resource_type, resource_id);
    END IF;
END $$;

-- ============================================
-- 11. Update audit.log_event function
-- ============================================

CREATE OR REPLACE FUNCTION audit.log_event(
    p_tenant_id UUID,
    p_user_id UUID,
    p_action audit.action_type,
    p_resource_type VARCHAR,
    p_resource_id VARCHAR DEFAULT NULL,
    p_resource_name VARCHAR DEFAULT NULL,
    p_description TEXT DEFAULT NULL,
    p_old_values JSONB DEFAULT NULL,
    p_new_values JSONB DEFAULT NULL,
    p_changed_fields JSONB DEFAULT NULL,
    p_metadata JSONB DEFAULT '{}'::jsonb,
    p_severity audit.severity DEFAULT 'info'
)
RETURNS UUID AS $$
DECLARE
    v_id UUID;
    v_user_email VARCHAR(255);
BEGIN
    -- Get user email for denormalization
    SELECT email INTO v_user_email
    FROM users.users
    WHERE id = p_user_id;

    INSERT INTO audit.audit_logs (
        tenant_id, user_id, user_email, action, resource_type, resource_id,
        resource_name, description, old_values, new_values, changed_fields,
        metadata, severity
    ) VALUES (
        p_tenant_id, p_user_id, v_user_email, p_action, p_resource_type, p_resource_id,
        p_resource_name, p_description, p_old_values, p_new_values, p_changed_fields,
        p_metadata, p_severity
    ) RETURNING id INTO v_id;

    RETURN v_id;
END;
$$ LANGUAGE plpgsql;

-- ============================================
-- 12. Update comments
-- ============================================

COMMENT ON COLUMN audit.audit_logs.user_email IS 'Denormalized user email for fast queries';
COMMENT ON COLUMN audit.audit_logs.actor_type IS 'Type of actor: user, system, api_key, webhook';
COMMENT ON COLUMN audit.audit_logs.resource_type IS 'Type of resource: user, product, invoice, etc.';
COMMENT ON COLUMN audit.audit_logs.resource_id IS 'ID of the affected resource';
COMMENT ON COLUMN audit.audit_logs.resource_name IS 'Human-readable name of the resource';
COMMENT ON COLUMN audit.audit_logs.severity IS 'Log severity level: info, warning, error, critical';
COMMENT ON COLUMN audit.audit_logs.request_id IS 'Correlation ID for request tracing';
COMMENT ON COLUMN audit.audit_logs.session_id IS 'Session ID for session correlation';
COMMENT ON COLUMN audit.audit_logs.endpoint IS 'API endpoint path';
COMMENT ON COLUMN audit.audit_logs.http_method IS 'HTTP method: GET, POST, PUT, DELETE, etc.';
COMMENT ON COLUMN audit.audit_logs.response_status IS 'HTTP response status code';
COMMENT ON COLUMN audit.audit_logs.duration_ms IS 'Request duration in milliseconds';
COMMENT ON COLUMN audit.audit_logs.old_values IS 'Previous values before change';
COMMENT ON COLUMN audit.audit_logs.new_values IS 'New values after change';
COMMENT ON COLUMN audit.audit_logs.changed_fields IS 'List of fields that were changed';

COMMIT;
