-- ============================================
-- TEMPLATE-SAAS: Audit Logs
-- Schema: audit
-- Version: 1.0.0
-- ============================================

CREATE TABLE audit.audit_logs (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES tenants.tenants(id) ON DELETE CASCADE,

    -- Actor
    user_id UUID REFERENCES users.users(id),
    user_email VARCHAR(255),
    actor_type VARCHAR(50) DEFAULT 'user',  -- 'user', 'system', 'api_key', 'webhook'

    -- Action
    action audit.action_type NOT NULL,
    resource_type VARCHAR(100) NOT NULL,  -- 'user', 'product', 'invoice', etc.
    resource_id VARCHAR(255),
    resource_name VARCHAR(255),

    -- Details
    description TEXT,
    changes JSONB,  -- { "field": { "old": x, "new": y } }
    metadata JSONB DEFAULT '{}'::jsonb,

    -- Severity
    severity audit.severity DEFAULT 'info',

    -- Context
    ip_address INET,
    user_agent TEXT,
    request_id VARCHAR(100),
    session_id UUID,

    -- Timestamp
    created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,

    -- Partitioning support (optional)
    partition_key DATE DEFAULT CURRENT_DATE
);

-- Activity logs (lighter weight, for analytics)
CREATE TABLE audit.activity_logs (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES tenants.tenants(id) ON DELETE CASCADE,
    user_id UUID REFERENCES users.users(id),

    -- Activity
    activity_type VARCHAR(100) NOT NULL,  -- 'page_view', 'button_click', 'search', etc.
    page_url VARCHAR(500),
    referrer VARCHAR(500),

    -- Context
    session_id UUID,
    device_type VARCHAR(50),
    browser VARCHAR(100),
    os VARCHAR(100),

    -- Data
    data JSONB DEFAULT '{}'::jsonb,

    -- Timestamp
    created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL
);

-- Indexes
CREATE INDEX idx_audit_logs_tenant ON audit.audit_logs(tenant_id, created_at DESC);
CREATE INDEX idx_audit_logs_user ON audit.audit_logs(tenant_id, user_id, created_at DESC);
CREATE INDEX idx_audit_logs_resource ON audit.audit_logs(tenant_id, resource_type, resource_id);
CREATE INDEX idx_audit_logs_action ON audit.audit_logs(tenant_id, action, created_at DESC);
CREATE INDEX idx_audit_logs_severity ON audit.audit_logs(tenant_id, severity) WHERE severity IN ('warning', 'error', 'critical');

CREATE INDEX idx_activity_logs_tenant ON audit.activity_logs(tenant_id, created_at DESC);
CREATE INDEX idx_activity_logs_user ON audit.activity_logs(tenant_id, user_id, created_at DESC);
CREATE INDEX idx_activity_logs_type ON audit.activity_logs(tenant_id, activity_type);

-- RLS
ALTER TABLE audit.audit_logs ENABLE ROW LEVEL SECURITY;
ALTER TABLE audit.activity_logs ENABLE ROW LEVEL SECURITY;

CREATE POLICY audit_logs_tenant_isolation ON audit.audit_logs
    USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);

CREATE POLICY activity_logs_tenant_isolation ON audit.activity_logs
    USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);

-- Function to log audit event
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_changes JSONB DEFAULT NULL,
    p_metadata JSONB DEFAULT '{}'::jsonb,
    p_severity audit.severity DEFAULT 'info'
)
RETURNS UUID AS $$
DECLARE
    v_id UUID;
BEGIN
    INSERT INTO audit.audit_logs (
        tenant_id, user_id, action, resource_type, resource_id,
        resource_name, description, changes, metadata, severity
    ) VALUES (
        p_tenant_id, p_user_id, p_action, p_resource_type, p_resource_id,
        p_resource_name, p_description, p_changes, p_metadata, p_severity
    ) RETURNING id INTO v_id;

    RETURN v_id;
END;
$$ LANGUAGE plpgsql;

-- Retention policy function
CREATE OR REPLACE FUNCTION audit.cleanup_old_logs(retention_days INT DEFAULT 90)
RETURNS INTEGER AS $$
DECLARE
    deleted_count INTEGER;
BEGIN
    WITH deleted AS (
        DELETE FROM audit.audit_logs
        WHERE created_at < NOW() - (retention_days || ' days')::INTERVAL
        AND severity NOT IN ('error', 'critical')
        RETURNING *
    )
    SELECT COUNT(*) INTO deleted_count FROM deleted;

    DELETE FROM audit.activity_logs
    WHERE created_at < NOW() - (retention_days || ' days')::INTERVAL;

    RETURN deleted_count;
END;
$$ LANGUAGE plpgsql;

-- Comments
COMMENT ON TABLE audit.audit_logs IS 'Comprehensive audit trail for compliance';
COMMENT ON TABLE audit.activity_logs IS 'User activity tracking for analytics';
COMMENT ON COLUMN audit.audit_logs.changes IS 'JSON diff of field changes';
