import { hubspotAuth } from '../auth';
import { createAction, Property } from '@activepieces/pieces-framework';
import {
	fromObjectTypeAssociationDropdown,
	associationTypeDropdown,
	toObjectIdsDropdown,
} from '../common/props';
import { OBJECT_TYPE } from '../common/constants';
import { Client } from '@hubspot/api-client';
import { AssociationSpecAssociationCategoryEnum } from '../common/types';
import { chunk } from '@activepieces/pieces-framework';

export const createAssociationsAction = createAction({
	auth: hubspotAuth,
	name: 'create-associations',
	displayName: 'Create Associations',
	description: 'Creates associations between objects',
	audience: 'both',
	aiMetadata: { description: 'Link one source HubSpot object (e.g. a company) to one or more target objects using a specific association type, batching the targets. Re-running with the same inputs re-applies the same association without creating duplicates. Use Remove Associations to undo a link.', idempotent: true },
	props: {
		fromObjectId: Property.ShortText({
			displayName: 'From Object ID',
			description: 'The ID of the object being associated.',
			required: true,
		}),
		fromObjectType: fromObjectTypeAssociationDropdown({
			objectType: OBJECT_TYPE.COMPANY,
			displayName: 'From Object Type',
			required: true,
			description: 'The type of the object being associated.',
		}),
		toObjectType: fromObjectTypeAssociationDropdown({
			objectType: OBJECT_TYPE.COMPANY,
			displayName: 'To Object Type',
			required: true,
			description: 'Type of the objects the from object is being associated with.',
		}),
		associationType: associationTypeDropdown,
		toObjectIds: toObjectIdsDropdown({
			objectType: OBJECT_TYPE.COMPANY,
			displayName: 'To Object IDs',
			required: true,
			description: 'The ID\'sof the objects the from object is being associated with',
		}),
	},
	async run(context) {
		const { fromObjectId, fromObjectType, toObjectType, associationType } = context.propsValue;

		const client = new Client({ accessToken: context.auth.access_token });

		if(context.propsValue.toObjectIds === undefined) {
			throw new Error('Please provide To Object IDs');
		}
		
		let toObjectIds: any[];
		if (Array.isArray(context.propsValue.toObjectIds)) {
			toObjectIds = context.propsValue.toObjectIds;
		} else {
			try {
				toObjectIds = JSON.parse(context.propsValue.toObjectIds);
			} catch {
				throw new Error(
					`Please provide To Object IDs in a valid format. Provided : ${JSON.stringify(
						context.propsValue.toObjectIds,
					)}`,
				);
			}
		}

		// find the association category
		const associationLabels = await client.crm.associations.v4.schema.definitionsApi.getAll(
			fromObjectType as string,
			toObjectType as string,
		);
		const association = associationLabels.results.find(
			(associationLabel) => associationLabel.typeId === associationType,
		);
		if (!association) {
			throw new Error(
				`Association type ${associationType} not found for ${fromObjectType} to ${toObjectType}`,
			);
		}
		const associationCategory = association.category;

		// Batch API limit is 1000, but using 100 for consistency and safety
		const BATCH_SIZE = 100;
		const chunks = chunk(toObjectIds, BATCH_SIZE);
		const responses = [];

		for (const chunkBatch of chunks) {
			const response = await client.crm.associations.v4.batchApi.create(
				fromObjectType as string,
				toObjectType as string,
				{
					inputs: chunkBatch.map((objectId) => {
						return {
							_from: {
								id: fromObjectId,
							},
							to: {
								id: objectId,
							},
							types: [
								{
									associationCategory:
										associationCategory as unknown as AssociationSpecAssociationCategoryEnum,
									associationTypeId: associationType,
								},
							],
						};
					}),
				},
			);
			responses.push(response);
		}

		return {
			totalAssociations: toObjectIds.length,
			batchCount: chunks.length,
			responses,
		};
	},
});
