-- ==========================================
-- Chat Switchboard — 004 Personas & Grants
-- ==========================================
-- Persona definitions, persona capability grants, and resource access grants.
-- ICD §4 (Personas)
-- ==========================================

-- =========================================
-- PERSONAS
-- =========================================

CREATE TABLE IF NOT EXISTS personas (
    id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name                VARCHAR(100) NOT NULL,
    handle              VARCHAR(50),
    description         TEXT DEFAULT '',
    icon                VARCHAR(10) DEFAULT '',
    avatar              TEXT DEFAULT '',

    -- Base model binding
    base_model_id       TEXT NOT NULL,
    provider_config_id  UUID REFERENCES provider_configs(id) ON DELETE SET NULL,

    -- Behavioral configuration
    system_prompt       TEXT DEFAULT '',
    temperature         FLOAT,
    max_tokens          INT,
    thinking_budget     INT,
    top_p               FLOAT,

    -- Memory configuration (v0.18.0)
    memory_enabled          BOOLEAN NOT NULL DEFAULT true,
    memory_extraction_prompt TEXT,

    -- Scope & ownership
    scope               VARCHAR(10) NOT NULL
                        CHECK (scope IN ('global', 'team', 'personal')),
    owner_id            UUID,
    created_by          UUID NOT NULL REFERENCES users(id),

    -- State
    is_active           BOOLEAN DEFAULT true,
    is_shared           BOOLEAN DEFAULT false,

    created_at          TIMESTAMPTZ DEFAULT NOW(),
    updated_at          TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_personas_scope ON personas(scope);
CREATE INDEX IF NOT EXISTS idx_personas_owner ON personas(owner_id) WHERE owner_id IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_personas_active ON personas(is_active) WHERE is_active = true;
CREATE UNIQUE INDEX IF NOT EXISTS idx_personas_handle ON personas(handle) WHERE handle IS NOT NULL;
DROP TRIGGER IF EXISTS personas_updated_at ON personas;
CREATE TRIGGER personas_updated_at BEFORE UPDATE ON personas
    FOR EACH ROW EXECUTE FUNCTION update_updated_at();

COMMENT ON COLUMN personas.scope IS 'global=all users, team=team members, personal=creator only';
COMMENT ON COLUMN personas.owner_id IS 'NULL for global; teams.id for team scope; users.id for personal';
COMMENT ON COLUMN personas.handle IS 'Unique @mention handle, e.g. veronica-sharpe. Auto-generated from name.';
COMMENT ON COLUMN personas.is_shared IS 'Personal personas shared with others (read-only)';
COMMENT ON COLUMN personas.memory_enabled IS 'Whether memory tools and extraction are active for this persona';
COMMENT ON COLUMN personas.memory_extraction_prompt IS 'Custom extraction prompt; NULL = use system default';


-- =========================================
-- PERSONA GROUPS (v0.23.0)
-- =========================================
-- Saved roster templates. A group is a named set of personas
-- that can be stamped onto any new conversation.

CREATE TABLE IF NOT EXISTS persona_groups (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name            VARCHAR(100) NOT NULL,
    description     TEXT DEFAULT '',
    owner_id        UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    scope           VARCHAR(10) NOT NULL DEFAULT 'personal'
                    CHECK (scope IN ('global', 'team', 'personal')),
    team_id         UUID REFERENCES teams(id) ON DELETE CASCADE,
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_persona_groups_owner ON persona_groups(owner_id);
DROP TRIGGER IF EXISTS persona_groups_updated_at ON persona_groups;
CREATE TRIGGER persona_groups_updated_at BEFORE UPDATE ON persona_groups
    FOR EACH ROW EXECUTE FUNCTION update_updated_at();

CREATE TABLE IF NOT EXISTS persona_group_members (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    group_id        UUID NOT NULL REFERENCES persona_groups(id) ON DELETE CASCADE,
    persona_id      UUID NOT NULL REFERENCES personas(id) ON DELETE CASCADE,
    is_leader       BOOLEAN NOT NULL DEFAULT false,
    sort_order      INT NOT NULL DEFAULT 0,
    UNIQUE(group_id, persona_id)
);

CREATE INDEX IF NOT EXISTS idx_persona_group_members_group ON persona_group_members(group_id);


-- =========================================
-- PERSONA GRANTS (what a persona can do)
-- =========================================

CREATE TABLE IF NOT EXISTS persona_grants (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    persona_id      UUID NOT NULL REFERENCES personas(id) ON DELETE CASCADE,
    grant_type      VARCHAR(30) NOT NULL,
    grant_ref       TEXT NOT NULL,
    config          JSONB DEFAULT '{}'::jsonb,
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(persona_id, grant_type, grant_ref)
);

CREATE INDEX IF NOT EXISTS idx_persona_grants_persona ON persona_grants(persona_id);
CREATE INDEX IF NOT EXISTS idx_persona_grants_type ON persona_grants(grant_type);

COMMENT ON TABLE persona_grants IS 'What a persona can do: tools it can call, KBs it can search, etc.';
COMMENT ON COLUMN persona_grants.grant_type IS 'Extensible: tool, knowledge_base, api_endpoint';
COMMENT ON COLUMN persona_grants.grant_ref IS 'tool: function name. knowledge_base: UUID. api_endpoint: identifier.';


-- =========================================
-- RESOURCE GRANTS (who can USE a resource)
-- =========================================

CREATE TABLE IF NOT EXISTS resource_grants (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    resource_type   VARCHAR(30) NOT NULL
                    CHECK (resource_type IN ('persona', 'knowledge_base', 'project')),
    resource_id     UUID NOT NULL,
    grant_scope     VARCHAR(20) NOT NULL DEFAULT 'team_only'
                    CHECK (grant_scope IN ('team_only', 'global', 'groups')),
    granted_groups  UUID[] NOT NULL DEFAULT '{}',
    created_by      UUID NOT NULL REFERENCES users(id),
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW(),

    UNIQUE(resource_type, resource_id)
);

CREATE INDEX IF NOT EXISTS idx_resource_grants_resource
    ON resource_grants(resource_type, resource_id);
CREATE INDEX IF NOT EXISTS idx_resource_grants_groups
    ON resource_grants USING gin(granted_groups);

DROP TRIGGER IF EXISTS resource_grants_updated_at ON resource_grants;
CREATE TRIGGER resource_grants_updated_at BEFORE UPDATE ON resource_grants
    FOR EACH ROW EXECUTE FUNCTION update_updated_at();

COMMENT ON TABLE resource_grants IS 'Who can USE a resource (personas, KBs, projects). Cross-team access via groups.';
COMMENT ON COLUMN resource_grants.grant_scope IS 'team_only: existing team behavior. global: all users. groups: specific group list.';
