-- ============================================
-- TEMPLATE-SAAS: Feature Flags
-- Schema: feature_flags
-- Version: 1.0.0
-- ============================================

-- Feature flag definitions (global)
CREATE TABLE feature_flags.flags (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    -- Flag identification
    code VARCHAR(100) UNIQUE NOT NULL,
    name VARCHAR(200) NOT NULL,
    description TEXT,
    category VARCHAR(100),  -- 'billing', 'ui', 'api', 'experimental'

    -- Status
    status feature_flags.flag_status DEFAULT 'disabled' NOT NULL,

    -- Rollout
    rollout_stage feature_flags.rollout_stage DEFAULT 'development',
    rollout_percentage INT DEFAULT 0,  -- 0-100

    -- Default value
    default_value BOOLEAN DEFAULT FALSE,

    -- Targeting rules (JSONB)
    targeting_rules JSONB DEFAULT '[]'::jsonb,
    -- Example:
    -- [
    --   { "type": "plan", "operator": "in", "values": ["pro", "enterprise"] },
    --   { "type": "user_attribute", "attribute": "country", "operator": "eq", "value": "MX" }
    -- ]

    -- Metadata
    metadata JSONB DEFAULT '{}'::jsonb,
    tags JSONB DEFAULT '[]'::jsonb,

    -- Lifecycle
    is_permanent BOOLEAN DEFAULT FALSE,  -- Won't be cleaned up
    expires_at TIMESTAMPTZ,

    -- Audit
    created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
    updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
    created_by VARCHAR(100),

    -- Constraints
    CONSTRAINT valid_flag_code CHECK (code ~ '^[a-z][a-z0-9_]*$'),
    CONSTRAINT valid_percentage CHECK (rollout_percentage >= 0 AND rollout_percentage <= 100)
);

-- Tenant-specific flag overrides
CREATE TABLE feature_flags.tenant_flags (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES tenants.tenants(id) ON DELETE CASCADE,
    flag_id UUID NOT NULL REFERENCES feature_flags.flags(id) ON DELETE CASCADE,

    -- Override value
    is_enabled BOOLEAN NOT NULL,

    -- Reason
    reason VARCHAR(500),

    -- Audit
    created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
    updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
    updated_by UUID,

    -- Constraints
    CONSTRAINT unique_tenant_flag UNIQUE (tenant_id, flag_id)
);

-- User-specific flag overrides
CREATE TABLE feature_flags.user_flags (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES tenants.tenants(id) ON DELETE CASCADE,
    user_id UUID NOT NULL REFERENCES users.users(id) ON DELETE CASCADE,
    flag_id UUID NOT NULL REFERENCES feature_flags.flags(id) ON DELETE CASCADE,

    -- Override value
    is_enabled BOOLEAN NOT NULL,

    -- Reason
    reason VARCHAR(500),

    -- Expiration
    expires_at TIMESTAMPTZ,

    -- Audit
    created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
    updated_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
    updated_by UUID,

    -- Constraints
    CONSTRAINT unique_user_flag UNIQUE (user_id, flag_id)
);

-- Flag evaluation history (for analytics)
CREATE TABLE feature_flags.evaluations (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES tenants.tenants(id) ON DELETE CASCADE,
    flag_id UUID NOT NULL REFERENCES feature_flags.flags(id) ON DELETE CASCADE,
    user_id UUID REFERENCES users.users(id),

    -- Result
    flag_code VARCHAR(100) NOT NULL,
    result BOOLEAN NOT NULL,
    evaluation_reason VARCHAR(100),  -- 'default', 'tenant_override', 'user_override', 'targeting_rule', 'percentage'

    -- Context
    context JSONB DEFAULT '{}'::jsonb,

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

-- Indexes
CREATE INDEX idx_flags_code ON feature_flags.flags(code);
CREATE INDEX idx_flags_status ON feature_flags.flags(status) WHERE status != 'disabled';
CREATE INDEX idx_flags_category ON feature_flags.flags(category);

CREATE INDEX idx_tenant_flags_tenant ON feature_flags.tenant_flags(tenant_id);
CREATE INDEX idx_tenant_flags_flag ON feature_flags.tenant_flags(flag_id);

CREATE INDEX idx_user_flags_user ON feature_flags.user_flags(user_id);
CREATE INDEX idx_user_flags_tenant ON feature_flags.user_flags(tenant_id);

CREATE INDEX idx_evaluations_tenant ON feature_flags.evaluations(tenant_id, created_at DESC);
CREATE INDEX idx_evaluations_flag ON feature_flags.evaluations(flag_id, created_at DESC);

-- RLS
ALTER TABLE feature_flags.tenant_flags ENABLE ROW LEVEL SECURITY;
ALTER TABLE feature_flags.user_flags ENABLE ROW LEVEL SECURITY;
ALTER TABLE feature_flags.evaluations ENABLE ROW LEVEL SECURITY;

CREATE POLICY tenant_flags_isolation ON feature_flags.tenant_flags
    USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);

CREATE POLICY user_flags_isolation ON feature_flags.user_flags
    USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);

CREATE POLICY evaluations_isolation ON feature_flags.evaluations
    USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);

-- Trigger
CREATE OR REPLACE FUNCTION feature_flags.update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = NOW();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_flags_updated_at
    BEFORE UPDATE ON feature_flags.flags
    FOR EACH ROW
    EXECUTE FUNCTION feature_flags.update_updated_at();

CREATE TRIGGER trg_tenant_flags_updated_at
    BEFORE UPDATE ON feature_flags.tenant_flags
    FOR EACH ROW
    EXECUTE FUNCTION feature_flags.update_updated_at();

CREATE TRIGGER trg_user_flags_updated_at
    BEFORE UPDATE ON feature_flags.user_flags
    FOR EACH ROW
    EXECUTE FUNCTION feature_flags.update_updated_at();

-- Function to evaluate flag
CREATE OR REPLACE FUNCTION feature_flags.evaluate_flag(
    p_flag_code VARCHAR,
    p_tenant_id UUID,
    p_user_id UUID DEFAULT NULL
)
RETURNS BOOLEAN AS $$
DECLARE
    v_flag RECORD;
    v_tenant_override RECORD;
    v_user_override RECORD;
    v_result BOOLEAN;
BEGIN
    -- Get flag
    SELECT * INTO v_flag FROM feature_flags.flags WHERE code = p_flag_code;

    IF NOT FOUND THEN
        RETURN FALSE;
    END IF;

    -- Check user override
    IF p_user_id IS NOT NULL THEN
        SELECT * INTO v_user_override
        FROM feature_flags.user_flags
        WHERE flag_id = v_flag.id AND user_id = p_user_id
        AND (expires_at IS NULL OR expires_at > NOW());

        IF FOUND THEN
            RETURN v_user_override.is_enabled;
        END IF;
    END IF;

    -- Check tenant override
    SELECT * INTO v_tenant_override
    FROM feature_flags.tenant_flags
    WHERE flag_id = v_flag.id AND tenant_id = p_tenant_id;

    IF FOUND THEN
        RETURN v_tenant_override.is_enabled;
    END IF;

    -- Check status
    IF v_flag.status = 'disabled' THEN
        RETURN FALSE;
    ELSIF v_flag.status = 'enabled' THEN
        RETURN TRUE;
    ELSIF v_flag.status = 'percentage' THEN
        -- Simple percentage rollout based on tenant_id
        RETURN (abs(hashtext(p_tenant_id::TEXT)) % 100) < v_flag.rollout_percentage;
    END IF;

    RETURN v_flag.default_value;
END;
$$ LANGUAGE plpgsql STABLE;

-- Comments
COMMENT ON TABLE feature_flags.flags IS 'Global feature flag definitions';
COMMENT ON TABLE feature_flags.tenant_flags IS 'Tenant-specific flag overrides';
COMMENT ON TABLE feature_flags.user_flags IS 'User-specific flag overrides';
COMMENT ON TABLE feature_flags.evaluations IS 'Flag evaluation history for analytics';
COMMENT ON COLUMN feature_flags.flags.targeting_rules IS 'JSON rules for advanced targeting';
