import { CredentialType } from '@bubblelab/shared-schemas';
import { ServiceBubble } from '../../../types/service-bubble-class.js';
import { AttioParamsSchema, AttioResultSchema, } from './attio.schema.js';
const ATTIO_API_BASE = 'https://api.attio.com/v2';
export class AttioBubble extends ServiceBubble {
    static service = 'attio';
    static authType = 'oauth';
    static bubbleName = 'attio';
    static type = 'service';
    static schema = AttioParamsSchema;
    static resultSchema = AttioResultSchema;
    static shortDescription = 'Attio CRM integration for managing records, notes, tasks, and lists';
    static longDescription = `
    Integrate with Attio CRM to manage your customer relationships.
    Supported operations:
    - Records: List, get, create, update, and delete records for any object type (people, companies, deals, custom objects)
    - Notes: Create and list notes linked to records
    - Tasks: Create, list, update, and delete CRM tasks with deadlines and assignees
    - Lists & Entries: Manage pipeline lists and add/query entries
    Authentication: OAuth2 with Bearer token
  `;
    static alias = 'attio';
    constructor(params = {
        operation: 'list_records',
        object: 'people',
    }, context) {
        super(params, context);
    }
    chooseCredential() {
        const params = this.params;
        const credentials = params.credentials;
        if (!credentials || typeof credentials !== 'object') {
            return undefined;
        }
        return credentials[CredentialType.ATTIO_CRED];
    }
    async makeAttioRequest(path, options = {}) {
        const token = this.chooseCredential();
        if (!token) {
            return { ok: false, error: 'Attio credential not found' };
        }
        const { method = 'GET', body, queryParams } = options;
        let url = `${ATTIO_API_BASE}${path}`;
        if (queryParams) {
            const params = new URLSearchParams(queryParams);
            url += `?${params.toString()}`;
        }
        const headers = {
            Authorization: `Bearer ${token}`,
            'Content-Type': 'application/json',
        };
        try {
            const fetchOptions = { method, headers };
            if (body && method !== 'GET') {
                fetchOptions.body = JSON.stringify(body);
            }
            const response = await fetch(url, fetchOptions);
            const text = await response.text();
            if (!response.ok) {
                let errorMessage = `Attio API error (${response.status})`;
                try {
                    const errorData = JSON.parse(text);
                    errorMessage = errorData.message || errorData.error || errorMessage;
                }
                catch {
                    if (text)
                        errorMessage += `: ${text.slice(0, 200)}`;
                }
                return { ok: false, error: errorMessage };
            }
            if (!text || text.trim() === '') {
                return { ok: true };
            }
            const data = JSON.parse(text);
            return { ok: true, data };
        }
        catch (error) {
            return {
                ok: false,
                error: error instanceof Error ? error.message : 'Unknown error occurred',
            };
        }
    }
    async testCredential() {
        const token = this.chooseCredential();
        if (!token) {
            throw new Error('Attio credentials are required');
        }
        const response = await fetch(`${ATTIO_API_BASE}/self`, {
            method: 'GET',
            headers: {
                Authorization: `Bearer ${token}`,
                'Content-Type': 'application/json',
            },
        });
        if (!response.ok) {
            const text = await response.text();
            throw new Error(`Attio API error (${response.status}): ${text}`);
        }
        return true;
    }
    async performAction(context) {
        void context;
        const params = this.params;
        const { operation } = params;
        try {
            switch (operation) {
                case 'list_records':
                    return (await this.listRecords(params));
                case 'get_record':
                    return (await this.getRecord(params));
                case 'create_record':
                    return (await this.createRecord(params));
                case 'update_record':
                    return (await this.updateRecord(params));
                case 'delete_record':
                    return (await this.deleteRecord(params));
                case 'create_note':
                    return (await this.createNote(params));
                case 'list_notes':
                    return (await this.listNotes(params));
                case 'create_task':
                    return (await this.createTask(params));
                case 'list_tasks':
                    return (await this.listTasks(params));
                case 'update_task':
                    return (await this.updateTask(params));
                case 'delete_task':
                    return (await this.deleteTask(params));
                case 'list_lists':
                    return (await this.listLists(params));
                case 'create_entry':
                    return (await this.createEntry(params));
                case 'list_entries':
                    return (await this.listEntries(params));
                default:
                    throw new Error(`Unknown operation: ${operation}`);
            }
        }
        catch (error) {
            return {
                operation,
                success: false,
                error: error instanceof Error ? error.message : 'Unknown error occurred',
            };
        }
    }
    // ========================== Records ==========================
    async listRecords(params) {
        const body = {
            limit: params.limit,
            offset: params.offset,
        };
        if (params.sorts)
            body.sorts = params.sorts;
        if (params.filter)
            body.filter = params.filter;
        const result = await this.makeAttioRequest(`/objects/${encodeURIComponent(params.object)}/records/query`, { method: 'POST', body });
        if (!result.ok) {
            return {
                operation: 'list_records',
                success: false,
                error: result.error || 'Failed to list records',
            };
        }
        const responseData = result.data;
        return {
            operation: 'list_records',
            records: responseData?.data || [],
            next_page_offset: (params.offset ?? 0) + (params.limit ?? 25),
            success: true,
            error: '',
        };
    }
    async getRecord(params) {
        const result = await this.makeAttioRequest(`/objects/${encodeURIComponent(params.object)}/records/${encodeURIComponent(params.record_id)}`);
        if (!result.ok) {
            return {
                operation: 'get_record',
                success: false,
                error: result.error || 'Failed to get record',
            };
        }
        const responseData = result.data;
        return {
            operation: 'get_record',
            record: responseData?.data,
            success: true,
            error: '',
        };
    }
    /**
     * Auto-fill `full_name` on personal-name values when only first/last are provided.
     * Attio rejects name values without `full_name`.
     */
    normalizeValues(values) {
        if (!values.name || !Array.isArray(values.name))
            return values;
        const normalized = { ...values };
        normalized.name = values.name.map((v) => {
            if (v.full_name || (!v.first_name && !v.last_name))
                return v;
            return {
                ...v,
                full_name: [v.first_name, v.last_name].filter(Boolean).join(' '),
            };
        });
        return normalized;
    }
    async createRecord(params) {
        const body = {
            data: { values: this.normalizeValues(params.values) },
        };
        const path = `/objects/${encodeURIComponent(params.object)}/records`;
        let method = 'POST';
        let queryParams;
        if (params.matching_attribute) {
            method = 'PUT';
            queryParams = { matching_attribute: params.matching_attribute };
        }
        const result = await this.makeAttioRequest(path, {
            method,
            body,
            queryParams,
        });
        if (!result.ok) {
            return {
                operation: 'create_record',
                success: false,
                error: result.error || 'Failed to create record',
            };
        }
        const responseData = result.data;
        return {
            operation: 'create_record',
            record: responseData?.data,
            success: true,
            error: '',
        };
    }
    async updateRecord(params) {
        const result = await this.makeAttioRequest(`/objects/${encodeURIComponent(params.object)}/records/${encodeURIComponent(params.record_id)}`, {
            method: 'PATCH',
            body: { data: { values: this.normalizeValues(params.values) } },
        });
        if (!result.ok) {
            return {
                operation: 'update_record',
                success: false,
                error: result.error || 'Failed to update record',
            };
        }
        const responseData = result.data;
        return {
            operation: 'update_record',
            record: responseData?.data,
            success: true,
            error: '',
        };
    }
    async deleteRecord(params) {
        const result = await this.makeAttioRequest(`/objects/${encodeURIComponent(params.object)}/records/${encodeURIComponent(params.record_id)}`, { method: 'DELETE' });
        return {
            operation: 'delete_record',
            success: result.ok,
            error: result.ok ? '' : result.error || 'Failed to delete record',
        };
    }
    // ========================== Notes ==========================
    async createNote(params) {
        const result = await this.makeAttioRequest('/notes', {
            method: 'POST',
            body: {
                data: {
                    title: params.title,
                    content: params.content,
                    format: params.format,
                    parent_object: params.parent_object,
                    parent_record_id: params.parent_record_id,
                },
            },
        });
        if (!result.ok) {
            return {
                operation: 'create_note',
                success: false,
                error: result.error || 'Failed to create note',
            };
        }
        const responseData = result.data;
        return {
            operation: 'create_note',
            note: responseData?.data,
            success: true,
            error: '',
        };
    }
    async listNotes(params) {
        const queryParams = {
            limit: String(params.limit),
            offset: String(params.offset),
        };
        if (params.parent_object)
            queryParams.parent_object = params.parent_object;
        if (params.parent_record_id)
            queryParams.parent_record_id = params.parent_record_id;
        const result = await this.makeAttioRequest('/notes', { queryParams });
        if (!result.ok) {
            return {
                operation: 'list_notes',
                success: false,
                error: result.error || 'Failed to list notes',
            };
        }
        const responseData = result.data;
        return {
            operation: 'list_notes',
            notes: responseData?.data || [],
            success: true,
            error: '',
        };
    }
    // ========================== Tasks ==========================
    async createTask(params) {
        const taskData = {
            content: params.content,
            format: 'plaintext',
            is_completed: params.is_completed ?? false,
            deadline_at: params.deadline_at ?? null,
            linked_records: params.linked_records ?? [],
            assignees: params.assignees ?? [],
        };
        const result = await this.makeAttioRequest('/tasks', {
            method: 'POST',
            body: { data: taskData },
        });
        if (!result.ok) {
            return {
                operation: 'create_task',
                success: false,
                error: result.error || 'Failed to create task',
            };
        }
        const responseData = result.data;
        return {
            operation: 'create_task',
            task: responseData?.data,
            success: true,
            error: '',
        };
    }
    async listTasks(params) {
        const result = await this.makeAttioRequest('/tasks', {
            queryParams: {
                limit: String(params.limit),
                offset: String(params.offset),
            },
        });
        if (!result.ok) {
            return {
                operation: 'list_tasks',
                success: false,
                error: result.error || 'Failed to list tasks',
            };
        }
        const responseData = result.data;
        return {
            operation: 'list_tasks',
            tasks: responseData?.data || [],
            success: true,
            error: '',
        };
    }
    async updateTask(params) {
        const taskData = {};
        if (params.content !== undefined)
            taskData.content = params.content;
        if (params.deadline_at !== undefined)
            taskData.deadline_at = params.deadline_at;
        if (params.is_completed !== undefined)
            taskData.is_completed = params.is_completed;
        const result = await this.makeAttioRequest(`/tasks/${encodeURIComponent(params.task_id)}`, {
            method: 'PATCH',
            body: { data: taskData },
        });
        if (!result.ok) {
            return {
                operation: 'update_task',
                success: false,
                error: result.error || 'Failed to update task',
            };
        }
        const responseData = result.data;
        return {
            operation: 'update_task',
            task: responseData?.data,
            success: true,
            error: '',
        };
    }
    async deleteTask(params) {
        const result = await this.makeAttioRequest(`/tasks/${encodeURIComponent(params.task_id)}`, { method: 'DELETE' });
        return {
            operation: 'delete_task',
            success: result.ok,
            error: result.ok ? '' : result.error || 'Failed to delete task',
        };
    }
    // ========================== Lists & Entries ==========================
    async listLists(params) {
        const result = await this.makeAttioRequest('/lists', {
            queryParams: {
                limit: String(params.limit),
                offset: String(params.offset),
            },
        });
        if (!result.ok) {
            return {
                operation: 'list_lists',
                success: false,
                error: result.error || 'Failed to list lists',
            };
        }
        const responseData = result.data;
        return {
            operation: 'list_lists',
            lists: responseData?.data || [],
            success: true,
            error: '',
        };
    }
    async createEntry(params) {
        const result = await this.makeAttioRequest(`/lists/${encodeURIComponent(params.list)}/entries`, {
            method: 'POST',
            body: {
                data: {
                    parent_object: params.parent_object,
                    parent_record_id: params.parent_record_id,
                    entry_values: params.entry_values,
                },
            },
        });
        if (!result.ok) {
            return {
                operation: 'create_entry',
                success: false,
                error: result.error || 'Failed to create entry',
            };
        }
        const responseData = result.data;
        return {
            operation: 'create_entry',
            entry: responseData?.data,
            success: true,
            error: '',
        };
    }
    async listEntries(params) {
        const body = {
            limit: params.limit,
            offset: params.offset,
        };
        if (params.filter)
            body.filter = params.filter;
        const result = await this.makeAttioRequest(`/lists/${encodeURIComponent(params.list)}/entries/query`, { method: 'POST', body });
        if (!result.ok) {
            return {
                operation: 'list_entries',
                success: false,
                error: result.error || 'Failed to list entries',
            };
        }
        const responseData = result.data;
        return {
            operation: 'list_entries',
            entries: responseData?.data || [],
            next_page_offset: (params.offset ?? 0) + (params.limit ?? 25),
            success: true,
            error: '',
        };
    }
}
//# sourceMappingURL=attio.js.map