import { ServiceBubble } from '../../../types/service-bubble-class.js';
import { CredentialType, decodeCredentialPayload, } from '@bubblelab/shared-schemas';
import { AsanaParamsSchema, AsanaResultSchema, } from './asana.schema.js';
const ASANA_API_BASE = 'https://app.asana.com/api/1.0';
/**
 * Asana Service Bubble
 *
 * Comprehensive Asana integration for managing tasks, projects, sections,
 * comments, users, teams, tags, and more via the Asana REST API.
 */
export class AsanaBubble extends ServiceBubble {
    static type = 'service';
    static service = 'asana';
    static authType = 'oauth';
    static bubbleName = 'asana';
    static schema = AsanaParamsSchema;
    static resultSchema = AsanaResultSchema;
    static shortDescription = 'Asana integration for tasks, projects, and team collaboration';
    static longDescription = `
    Comprehensive Asana project management integration.

    Features:
    - Create, read, update, delete, and search tasks
    - Manage projects, sections, and project memberships
    - Add comments and view task activity stories
    - List users, teams, and team members
    - Manage tags and custom fields
    - View attachments and workspaces
    - Filter tasks by project, section, assignee, dates, and completion status

    Security Features:
    - OAuth 2.0 authentication with Asana
    - Workspace-scoped access
    - Secure credential handling with base64-encoded payloads
  `;
    static alias = '';
    constructor(params = {
        operation: 'list_tasks',
        project: '',
    }, context) {
        super(params, context);
    }
    async testCredential() {
        const creds = this.parseCredentials();
        if (!creds) {
            throw new Error('Asana credentials are required');
        }
        const response = await fetch(`${ASANA_API_BASE}/users/me`, {
            headers: {
                Authorization: `Bearer ${creds.accessToken}`,
                Accept: 'application/json',
            },
        });
        if (!response.ok) {
            const text = await response.text();
            throw new Error(`Asana API error (${response.status}): ${text}`);
        }
        return true;
    }
    parseCredentials() {
        const { credentials } = this.params;
        if (!credentials || typeof credentials !== 'object') {
            return null;
        }
        const raw = credentials[CredentialType.ASANA_CRED];
        if (!raw) {
            return null;
        }
        try {
            const parsed = decodeCredentialPayload(raw);
            if (parsed.accessToken) {
                return {
                    accessToken: parsed.accessToken,
                    workspaceId: parsed.workspaceId || '',
                };
            }
        }
        catch {
            // If decoding fails, treat the raw value as an access token (validator path)
        }
        return { accessToken: raw, workspaceId: '' };
    }
    chooseCredential() {
        const creds = this.parseCredentials();
        return creds?.accessToken;
    }
    /** Resolve workspace GID from params or credential metadata. */
    getWorkspaceId(paramsWorkspace) {
        if (paramsWorkspace)
            return paramsWorkspace;
        const creds = this.parseCredentials();
        if (creds?.workspaceId)
            return creds.workspaceId;
        throw new Error('Workspace GID is required. Provide it in the workspace parameter or ensure your Asana credential has workspace metadata.');
    }
    // ─── API Request Helper ─────────────────────────────────────────────
    async asanaRequest(endpoint, method = 'GET', body) {
        const creds = this.parseCredentials();
        if (!creds) {
            throw new Error('Asana credentials are required');
        }
        const url = `${ASANA_API_BASE}${endpoint}`;
        const init = {
            method,
            headers: {
                Authorization: `Bearer ${creds.accessToken}`,
                'Content-Type': 'application/json',
                Accept: 'application/json',
            },
        };
        if (body && method !== 'GET') {
            init.body = JSON.stringify(body);
        }
        const response = await fetch(url, init);
        if (!response.ok) {
            const errorText = await response.text();
            let message = `Asana API error (${response.status})`;
            try {
                const errorJson = JSON.parse(errorText);
                if (errorJson.errors?.[0]?.message) {
                    message += `: ${errorJson.errors[0].message}`;
                }
                else {
                    message += `: ${errorText}`;
                }
            }
            catch {
                message += `: ${errorText}`;
            }
            throw new Error(message);
        }
        if (response.status === 204) {
            return undefined;
        }
        return await response.json();
    }
    /** Build opt_fields query param string. */
    buildOptFields(opt_fields) {
        if (!opt_fields || opt_fields.length === 0)
            return '';
        return `opt_fields=${opt_fields.join(',')}`;
    }
    /** Build query string from params object, omitting undefined/empty values. */
    buildQuery(params) {
        const parts = [];
        for (const [key, value] of Object.entries(params)) {
            if (value !== undefined && value !== '') {
                parts.push(`${key}=${encodeURIComponent(String(value))}`);
            }
        }
        return parts.length > 0 ? `?${parts.join('&')}` : '';
    }
    // ─── Action Dispatcher ──────────────────────────────────────────────
    async performAction(context) {
        void context;
        const { operation } = this.params;
        try {
            const result = await (async () => {
                const p = this.params;
                switch (operation) {
                    // Tasks
                    case 'list_tasks':
                        return await this.listTasks(p);
                    case 'get_task':
                        return await this.getTask(p);
                    case 'create_task':
                        return await this.createTask(p);
                    case 'update_task':
                        return await this.updateTask(p);
                    case 'delete_task':
                        return await this.deleteTask(p);
                    case 'search_tasks':
                        return await this.searchTasks(p);
                    case 'add_task_to_section':
                        return await this.addTaskToSection(p);
                    case 'set_dependencies':
                        return await this.setDependencies(p);
                    // Projects
                    case 'list_projects':
                        return await this.listProjects(p);
                    case 'get_project':
                        return await this.getProject(p);
                    case 'create_project':
                        return await this.createProject(p);
                    case 'update_project':
                        return await this.updateProject(p);
                    case 'list_sections':
                        return await this.listSections(p);
                    case 'create_section':
                        return await this.createSection(p);
                    // Comments / Stories
                    case 'add_comment':
                        return await this.addComment(p);
                    case 'get_task_stories':
                        return await this.getTaskStories(p);
                    // Users & Teams
                    case 'list_users':
                        return await this.listUsers(p);
                    case 'get_user':
                        return await this.getUser(p);
                    case 'list_teams':
                        return await this.listTeams(p);
                    case 'list_team_members':
                        return await this.listTeamMembers(p);
                    // Tags
                    case 'list_tags':
                        return await this.listTags(p);
                    case 'create_tag':
                        return await this.createTag(p);
                    case 'add_tag_to_task':
                        return await this.addTagToTask(p);
                    case 'remove_tag_from_task':
                        return await this.removeTagFromTask(p);
                    // Workspaces
                    case 'list_workspaces':
                        return await this.listWorkspaces(p);
                    // Custom Fields
                    case 'list_custom_fields':
                        return await this.listCustomFields(p);
                    // Attachments
                    case 'list_attachments':
                        return await this.listAttachments(p);
                    // Subtasks
                    case 'list_subtasks':
                        return await this.listSubtasks(p);
                    // Task-Project Membership
                    case 'add_task_to_project':
                        return await this.addTaskToProject(p);
                    case 'remove_task_from_project':
                        return await this.removeTaskFromProject(p);
                    // Section Management
                    case 'update_section':
                        return await this.updateSection(p);
                    case 'delete_section':
                        return await this.deleteSection(p);
                    // Project Deletion
                    case 'delete_project':
                        return await this.deleteProject(p);
                    default:
                        throw new Error(`Unsupported operation: ${operation}`);
                }
            })();
            return result;
        }
        catch (error) {
            return {
                operation,
                success: false,
                error: error instanceof Error ? error.message : 'Unknown error occurred',
            };
        }
    }
    // ─── Task Operations ────────────────────────────────────────────────
    async listTasks(params) {
        const queryParams = {
            limit: params.limit,
            completed_since: params.completed_since,
            modified_since: params.modified_since,
        };
        if (params.opt_fields?.length) {
            queryParams.opt_fields = params.opt_fields.join(',');
        }
        if (params.section) {
            queryParams.section = params.section;
        }
        else if (params.project) {
            queryParams.project = params.project;
        }
        else if (params.assignee) {
            queryParams.assignee = params.assignee;
            queryParams.workspace = this.getWorkspaceId(params.workspace);
        }
        else {
            throw new Error('At least one of project, section, or assignee must be provided');
        }
        const qs = this.buildQuery(queryParams);
        const data = (await this.asanaRequest(`/tasks${qs}`));
        return {
            operation: 'list_tasks',
            success: true,
            tasks: data.data,
            error: '',
        };
    }
    async getTask(params) {
        const optFields = this.buildOptFields(params.opt_fields);
        const qs = optFields ? `?${optFields}` : '';
        const data = (await this.asanaRequest(`/tasks/${params.task_gid}${qs}`));
        return {
            operation: 'get_task',
            success: true,
            task: data.data,
            error: '',
        };
    }
    async createTask(params) {
        const body = { name: params.name };
        if (params.notes)
            body.notes = params.notes;
        if (params.html_notes)
            body.html_notes = params.html_notes;
        if (params.assignee)
            body.assignee = params.assignee;
        if (params.due_on)
            body.due_on = params.due_on;
        if (params.due_at)
            body.due_at = params.due_at;
        if (params.start_on)
            body.start_on = params.start_on;
        if (params.projects)
            body.projects = params.projects;
        if (params.memberships)
            body.memberships = params.memberships;
        if (params.tags)
            body.tags = params.tags;
        if (params.parent)
            body.parent = params.parent;
        if (params.custom_fields)
            body.custom_fields = params.custom_fields;
        // If no project or parent specified, workspace is required
        if (!params.projects?.length &&
            !params.parent &&
            !params.memberships?.length) {
            body.workspace = this.getWorkspaceId(params.workspace);
        }
        const data = (await this.asanaRequest('/tasks', 'POST', {
            data: body,
        }));
        return {
            operation: 'create_task',
            success: true,
            task: data.data,
            error: '',
        };
    }
    async updateTask(params) {
        const body = {};
        if (params.name !== undefined)
            body.name = params.name;
        if (params.notes !== undefined)
            body.notes = params.notes;
        if (params.html_notes !== undefined)
            body.html_notes = params.html_notes;
        if (params.assignee !== undefined)
            body.assignee = params.assignee;
        if (params.due_on !== undefined)
            body.due_on = params.due_on;
        if (params.due_at !== undefined)
            body.due_at = params.due_at;
        if (params.start_on !== undefined)
            body.start_on = params.start_on;
        if (params.completed !== undefined)
            body.completed = params.completed;
        if (params.custom_fields !== undefined)
            body.custom_fields = params.custom_fields;
        const data = (await this.asanaRequest(`/tasks/${params.task_gid}`, 'PUT', {
            data: body,
        }));
        return {
            operation: 'update_task',
            success: true,
            task: data.data,
            error: '',
        };
    }
    async deleteTask(params) {
        await this.asanaRequest(`/tasks/${params.task_gid}`, 'DELETE');
        return {
            operation: 'delete_task',
            success: true,
            error: '',
        };
    }
    async searchTasks(params) {
        const workspaceId = this.getWorkspaceId(params.workspace);
        const queryParams = {
            limit: params.limit,
            sort_by: params.sort_by,
            sort_ascending: params.sort_ascending,
        };
        if (params.text)
            queryParams['text'] = params.text;
        if (params.assignee)
            queryParams['assignee.any'] = params.assignee;
        if (params.projects?.length)
            queryParams['projects.any'] = params.projects.join(',');
        if (params.completed !== undefined)
            queryParams['completed'] = params.completed;
        if (params.is_subtask !== undefined)
            queryParams['is_subtask'] = params.is_subtask;
        if (params.opt_fields?.length)
            queryParams['opt_fields'] = params.opt_fields.join(',');
        const qs = this.buildQuery(queryParams);
        const data = (await this.asanaRequest(`/workspaces/${workspaceId}/tasks/search${qs}`));
        return {
            operation: 'search_tasks',
            success: true,
            tasks: data.data,
            error: '',
        };
    }
    async addTaskToSection(params) {
        const body = { task: params.task_gid };
        if (params.insert_before)
            body.insert_before = params.insert_before;
        if (params.insert_after)
            body.insert_after = params.insert_after;
        await this.asanaRequest(`/sections/${params.section_gid}/addTask`, 'POST', {
            data: body,
        });
        return {
            operation: 'add_task_to_section',
            success: true,
            error: '',
        };
    }
    async setDependencies(params) {
        await this.asanaRequest(`/tasks/${params.task_gid}/addDependencies`, 'POST', { data: { dependencies: params.dependencies } });
        return {
            operation: 'set_dependencies',
            success: true,
            error: '',
        };
    }
    // ─── Project Operations ─────────────────────────────────────────────
    async listProjects(params) {
        const queryParams = {
            limit: params.limit,
            archived: params.archived,
        };
        if (params.team) {
            queryParams.team = params.team;
        }
        else {
            queryParams.workspace = this.getWorkspaceId(params.workspace);
        }
        if (params.opt_fields?.length)
            queryParams.opt_fields = params.opt_fields.join(',');
        const qs = this.buildQuery(queryParams);
        const data = (await this.asanaRequest(`/projects${qs}`));
        return {
            operation: 'list_projects',
            success: true,
            projects: data.data,
            error: '',
        };
    }
    async getProject(params) {
        const optFields = this.buildOptFields(params.opt_fields);
        const qs = optFields ? `?${optFields}` : '';
        const data = (await this.asanaRequest(`/projects/${params.project_gid}${qs}`));
        return {
            operation: 'get_project',
            success: true,
            project: data.data,
            error: '',
        };
    }
    async createProject(params) {
        const body = {
            name: params.name,
            workspace: this.getWorkspaceId(params.workspace),
        };
        if (params.notes)
            body.notes = params.notes;
        if (params.team)
            body.team = params.team;
        if (params.color)
            body.color = params.color;
        if (params.layout)
            body.default_view = params.layout;
        if (params.is_template !== undefined)
            body.is_template = params.is_template;
        if (params.public !== undefined)
            body.public = params.public;
        const data = (await this.asanaRequest('/projects', 'POST', {
            data: body,
        }));
        return {
            operation: 'create_project',
            success: true,
            project: data.data,
            error: '',
        };
    }
    async updateProject(params) {
        const body = {};
        if (params.name !== undefined)
            body.name = params.name;
        if (params.notes !== undefined)
            body.notes = params.notes;
        if (params.color !== undefined)
            body.color = params.color;
        if (params.archived !== undefined)
            body.archived = params.archived;
        if (params.public !== undefined)
            body.public = params.public;
        if (params.due_on !== undefined)
            body.due_on = params.due_on;
        if (params.start_on !== undefined)
            body.start_on = params.start_on;
        const data = (await this.asanaRequest(`/projects/${params.project_gid}`, 'PUT', { data: body }));
        return {
            operation: 'update_project',
            success: true,
            project: data.data,
            error: '',
        };
    }
    async listSections(params) {
        const queryParams = {
            limit: params.limit,
        };
        if (params.opt_fields?.length)
            queryParams.opt_fields = params.opt_fields.join(',');
        const qs = this.buildQuery(queryParams);
        const data = (await this.asanaRequest(`/projects/${params.project_gid}/sections${qs}`));
        return {
            operation: 'list_sections',
            success: true,
            sections: data.data,
            error: '',
        };
    }
    async createSection(params) {
        const body = { name: params.name };
        if (params.insert_before)
            body.insert_before = params.insert_before;
        if (params.insert_after)
            body.insert_after = params.insert_after;
        const data = (await this.asanaRequest(`/projects/${params.project_gid}/sections`, 'POST', { data: body }));
        return {
            operation: 'create_section',
            success: true,
            section: data.data,
            error: '',
        };
    }
    // ─── Comment / Story Operations ─────────────────────────────────────
    async addComment(params) {
        const body = {};
        if (params.html_text) {
            body.html_text = params.html_text;
        }
        else if (params.text) {
            body.text = params.text;
        }
        else {
            throw new Error('Either text or html_text must be provided');
        }
        const data = (await this.asanaRequest(`/tasks/${params.task_gid}/stories`, 'POST', { data: body }));
        return {
            operation: 'add_comment',
            success: true,
            story: data.data,
            error: '',
        };
    }
    async getTaskStories(params) {
        const queryParams = {
            limit: params.limit,
        };
        if (params.opt_fields?.length)
            queryParams.opt_fields = params.opt_fields.join(',');
        const qs = this.buildQuery(queryParams);
        const data = (await this.asanaRequest(`/tasks/${params.task_gid}/stories${qs}`));
        return {
            operation: 'get_task_stories',
            success: true,
            stories: data.data,
            error: '',
        };
    }
    // ─── User & Team Operations ─────────────────────────────────────────
    async listUsers(params) {
        const workspaceId = this.getWorkspaceId(params.workspace);
        const queryParams = {
            workspace: workspaceId,
            limit: params.limit,
        };
        if (params.opt_fields?.length)
            queryParams.opt_fields = params.opt_fields.join(',');
        const qs = this.buildQuery(queryParams);
        const data = (await this.asanaRequest(`/users${qs}`));
        return {
            operation: 'list_users',
            success: true,
            users: data.data,
            error: '',
        };
    }
    async getUser(params) {
        const optFields = this.buildOptFields(params.opt_fields);
        const qs = optFields ? `?${optFields}` : '';
        const data = (await this.asanaRequest(`/users/${params.user_gid}${qs}`));
        return {
            operation: 'get_user',
            success: true,
            user: data.data,
            error: '',
        };
    }
    async listTeams(params) {
        const workspaceId = this.getWorkspaceId(params.workspace);
        const queryParams = {
            limit: params.limit,
        };
        if (params.opt_fields?.length)
            queryParams.opt_fields = params.opt_fields.join(',');
        const qs = this.buildQuery(queryParams);
        const data = (await this.asanaRequest(`/organizations/${workspaceId}/teams${qs}`));
        return {
            operation: 'list_teams',
            success: true,
            teams: data.data,
            error: '',
        };
    }
    async listTeamMembers(params) {
        const queryParams = {
            limit: params.limit,
        };
        if (params.opt_fields?.length)
            queryParams.opt_fields = params.opt_fields.join(',');
        const qs = this.buildQuery(queryParams);
        const data = (await this.asanaRequest(`/teams/${params.team_gid}/users${qs}`));
        return {
            operation: 'list_team_members',
            success: true,
            users: data.data,
            error: '',
        };
    }
    // ─── Tag Operations ─────────────────────────────────────────────────
    async listTags(params) {
        const workspaceId = this.getWorkspaceId(params.workspace);
        const queryParams = {
            workspace: workspaceId,
            limit: params.limit,
        };
        if (params.opt_fields?.length)
            queryParams.opt_fields = params.opt_fields.join(',');
        const qs = this.buildQuery(queryParams);
        const data = (await this.asanaRequest(`/tags${qs}`));
        return {
            operation: 'list_tags',
            success: true,
            tags: data.data,
            error: '',
        };
    }
    async createTag(params) {
        const body = {
            name: params.name,
            workspace: this.getWorkspaceId(params.workspace),
        };
        if (params.color)
            body.color = params.color;
        const data = (await this.asanaRequest('/tags', 'POST', {
            data: body,
        }));
        return {
            operation: 'create_tag',
            success: true,
            tag: data.data,
            error: '',
        };
    }
    async addTagToTask(params) {
        await this.asanaRequest(`/tasks/${params.task_gid}/addTag`, 'POST', {
            data: { tag: params.tag_gid },
        });
        return {
            operation: 'add_tag_to_task',
            success: true,
            error: '',
        };
    }
    async removeTagFromTask(params) {
        await this.asanaRequest(`/tasks/${params.task_gid}/removeTag`, 'POST', {
            data: { tag: params.tag_gid },
        });
        return {
            operation: 'remove_tag_from_task',
            success: true,
            error: '',
        };
    }
    // ─── Workspace Operations ──────────────────────────────────────────
    async listWorkspaces(params) {
        const queryParams = {
            limit: params.limit,
        };
        if (params.opt_fields?.length)
            queryParams.opt_fields = params.opt_fields.join(',');
        const qs = this.buildQuery(queryParams);
        const data = (await this.asanaRequest(`/workspaces${qs}`));
        return {
            operation: 'list_workspaces',
            success: true,
            workspaces: data.data,
            error: '',
        };
    }
    // ─── Custom Fields Operations ───────────────────────────────────────
    async listCustomFields(params) {
        const queryParams = {
            limit: params.limit,
        };
        if (params.opt_fields?.length)
            queryParams.opt_fields = params.opt_fields.join(',');
        const qs = this.buildQuery(queryParams);
        const data = (await this.asanaRequest(`/projects/${params.project_gid}/custom_field_settings${qs}`));
        return {
            operation: 'list_custom_fields',
            success: true,
            custom_fields: data.data,
            error: '',
        };
    }
    // ─── Attachment Operations ──────────────────────────────────────────
    async listAttachments(params) {
        const queryParams = {
            parent: params.task_gid,
            limit: params.limit,
        };
        if (params.opt_fields?.length)
            queryParams.opt_fields = params.opt_fields.join(',');
        const qs = this.buildQuery(queryParams);
        const data = (await this.asanaRequest(`/attachments${qs}`));
        return {
            operation: 'list_attachments',
            success: true,
            attachments: data.data,
            error: '',
        };
    }
    // ─── Subtask Operations ─────────────────────────────────────────────
    async listSubtasks(params) {
        const queryParams = {
            limit: params.limit,
        };
        if (params.opt_fields?.length)
            queryParams.opt_fields = params.opt_fields.join(',');
        const qs = this.buildQuery(queryParams);
        const data = (await this.asanaRequest(`/tasks/${params.task_gid}/subtasks${qs}`));
        return {
            operation: 'list_subtasks',
            success: true,
            tasks: data.data,
            error: '',
        };
    }
    // ─── Task-Project Membership Operations ─────────────────────────────
    async addTaskToProject(params) {
        const body = { project: params.project_gid };
        if (params.section_gid)
            body.section = params.section_gid;
        await this.asanaRequest(`/tasks/${params.task_gid}/addProject`, 'POST', {
            data: body,
        });
        return {
            operation: 'add_task_to_project',
            success: true,
            error: '',
        };
    }
    async removeTaskFromProject(params) {
        await this.asanaRequest(`/tasks/${params.task_gid}/removeProject`, 'POST', {
            data: { project: params.project_gid },
        });
        return {
            operation: 'remove_task_from_project',
            success: true,
            error: '',
        };
    }
    // ─── Section Management Operations ──────────────────────────────────
    async updateSection(params) {
        const body = {};
        if (params.name !== undefined)
            body.name = params.name;
        const data = (await this.asanaRequest(`/sections/${params.section_gid}`, 'PUT', { data: body }));
        return {
            operation: 'update_section',
            success: true,
            section: data.data,
            error: '',
        };
    }
    async deleteSection(params) {
        await this.asanaRequest(`/sections/${params.section_gid}`, 'DELETE');
        return {
            operation: 'delete_section',
            success: true,
            error: '',
        };
    }
    // ─── Project Deletion ───────────────────────────────────────────────
    async deleteProject(params) {
        await this.asanaRequest(`/projects/${params.project_gid}`, 'DELETE');
        return {
            operation: 'delete_project',
            success: true,
            error: '',
        };
    }
}
//# sourceMappingURL=asana.js.map