-- v0.19.0: Projects / Workspaces
--
-- New: projects table
-- New: project_channels junction table (1:1 channel→project)
-- New: project_knowledge_bases junction table
-- New: project_notes junction table
-- New: channels.project_id denormalized FK
-- Changed: resource_grants.resource_type CHECK includes 'project'
-- Deprecated: channels.folder (column retained, no longer written)

-- =========================================
-- 1. Projects Table
-- =========================================

CREATE TABLE IF NOT EXISTS projects (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name        VARCHAR(200) NOT NULL,
    description TEXT,
    color       VARCHAR(7),          -- hex color e.g. '#3B82F6'
    icon        VARCHAR(50),         -- emoji or icon name
    scope       VARCHAR(20) NOT NULL DEFAULT 'personal'
                CHECK (scope IN ('personal', 'team', 'global')),
    owner_id    UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    team_id     UUID REFERENCES teams(id) ON DELETE SET NULL,
    is_archived BOOLEAN NOT NULL DEFAULT false,
    settings    JSONB DEFAULT '{}'::jsonb,
    created_at  TIMESTAMPTZ DEFAULT NOW(),
    updated_at  TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_projects_owner ON projects(owner_id);
CREATE INDEX IF NOT EXISTS idx_projects_team  ON projects(team_id) WHERE team_id IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_projects_scope ON projects(scope);

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

COMMENT ON TABLE projects IS 'Organizes channels, KBs, and notes into named workspaces';
COMMENT ON COLUMN projects.scope IS 'personal=owner only, team=team members, global=all users';

-- =========================================
-- 2. Project ↔ Channel Junction
-- =========================================
-- One project per channel (UNIQUE on channel_id).
-- Source of truth for position and folder within the project.

CREATE TABLE IF NOT EXISTS project_channels (
    project_id  UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
    channel_id  UUID NOT NULL REFERENCES channels(id) ON DELETE CASCADE,
    position    INTEGER NOT NULL DEFAULT 0,
    folder      TEXT,                -- sub-folder within the project
    added_at    TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    PRIMARY KEY (project_id, channel_id),
    UNIQUE (channel_id)              -- one project per channel
);

CREATE INDEX IF NOT EXISTS idx_project_channels_project  ON project_channels(project_id);
CREATE INDEX IF NOT EXISTS idx_project_channels_channel  ON project_channels(channel_id);

COMMENT ON TABLE project_channels IS 'Links channels to projects. UNIQUE(channel_id) enforces one-project-per-channel.';
COMMENT ON COLUMN project_channels.position IS 'Sort order within the project sidebar group';
COMMENT ON COLUMN project_channels.folder IS 'Optional sub-folder path within the project';

-- =========================================
-- 3. Project ↔ Knowledge Base Junction
-- =========================================

CREATE TABLE IF NOT EXISTS project_knowledge_bases (
    project_id  UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
    kb_id       UUID NOT NULL REFERENCES knowledge_bases(id) ON DELETE CASCADE,
    auto_search BOOLEAN NOT NULL DEFAULT false,
    added_at    TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    PRIMARY KEY (project_id, kb_id)
);

CREATE INDEX IF NOT EXISTS idx_project_kb_project ON project_knowledge_bases(project_id);
CREATE INDEX IF NOT EXISTS idx_project_kb_kb      ON project_knowledge_bases(kb_id);

COMMENT ON TABLE project_knowledge_bases IS 'Binds KBs to Projects — injected at completion time for all project channels';
COMMENT ON COLUMN project_knowledge_bases.auto_search IS 'true = auto-prepend top-K results; false = kb_search tool only';

-- =========================================
-- 4. Project ↔ Note Junction
-- =========================================

CREATE TABLE IF NOT EXISTS project_notes (
    project_id  UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
    note_id     UUID NOT NULL REFERENCES notes(id) ON DELETE CASCADE,
    added_at    TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    PRIMARY KEY (project_id, note_id)
);

CREATE INDEX IF NOT EXISTS idx_project_notes_project ON project_notes(project_id);
CREATE INDEX IF NOT EXISTS idx_project_notes_note    ON project_notes(note_id);

COMMENT ON TABLE project_notes IS 'Links notes to projects for organizational grouping';

-- =========================================
-- 5. Denormalized project_id on Channels
-- =========================================
-- Fast sidebar query: SELECT ... FROM channels WHERE project_id = $1
-- Source of truth is project_channels; this is updated atomically.

ALTER TABLE channels
    ADD COLUMN IF NOT EXISTS project_id UUID REFERENCES projects(id) ON DELETE SET NULL;

CREATE INDEX IF NOT EXISTS idx_channels_project ON channels(project_id) WHERE project_id IS NOT NULL;

-- =========================================
-- 6. Extend resource_grants CHECK
-- =========================================
-- Add 'project' to allowed resource_type values.
-- Postgres ALTER TABLE ... ALTER CONSTRAINT is not supported; drop + re-add.

ALTER TABLE resource_grants DROP CONSTRAINT IF EXISTS resource_grants_resource_type_check;
ALTER TABLE resource_grants ADD CONSTRAINT resource_grants_resource_type_check
    CHECK (resource_type IN ('persona', 'knowledge_base', 'project'));

-- =========================================
-- 7. Best-effort folder → project migration
-- =========================================
-- Create a personal project for each distinct folder value, then
-- associate the channels. Skip if no folder values exist.
-- This is idempotent: re-running won't duplicate projects because
-- we check for existing project_id.

DO $$
DECLARE
    _folder TEXT;
    _user_id UUID;
    _proj_id UUID;
    _ch_id UUID;
BEGIN
    FOR _user_id, _folder IN
        SELECT DISTINCT user_id, folder FROM channels
        WHERE folder IS NOT NULL AND folder != '' AND project_id IS NULL
    LOOP
        -- Create project named after the folder
        INSERT INTO projects (name, scope, owner_id)
        VALUES (_folder, 'personal', _user_id)
        RETURNING id INTO _proj_id;

        -- Associate channels
        FOR _ch_id IN
            SELECT id FROM channels
            WHERE user_id = _user_id AND folder = _folder AND project_id IS NULL
        LOOP
            INSERT INTO project_channels (project_id, channel_id, position)
            VALUES (_proj_id, _ch_id, 0)
            ON CONFLICT DO NOTHING;

            UPDATE channels SET project_id = _proj_id WHERE id = _ch_id;
        END LOOP;
    END LOOP;
END
$$;
