import { ref, watch, type Ref } from 'vue'
import { cloneDeep, isEqual } from 'lodash-es'
import type { NodeErrorStrategy, NodeRetryConfig } from '@/nodes/Interface'

const DEFAULT_RETRY_CONFIG: NodeRetryConfig = {
	retry_enabled: false,
	max_retries: 0,
	retry_interval: 100
}

const VALID_ERROR_STRATEGY: NodeErrorStrategy[] = ['none', 'default-value', 'fail-branch']

const ensureRuntimeDefaults = <T>(value: T): T => {
	if (!value || typeof value !== 'object') {
		return value
	}

	const data = value as Record<string, any>
	const rawRetryConfig = data.retry_config || {}
	data.retry_config = {
		retry_enabled: Boolean(rawRetryConfig.retry_enabled),
		max_retries:
			typeof rawRetryConfig.max_retries === 'number'
				? Math.max(0, Math.floor(rawRetryConfig.max_retries))
				: DEFAULT_RETRY_CONFIG.max_retries,
		retry_interval:
			typeof rawRetryConfig.retry_interval === 'number'
				? Math.max(100, Math.floor(rawRetryConfig.retry_interval))
				: DEFAULT_RETRY_CONFIG.retry_interval
	}

	if (!VALID_ERROR_STRATEGY.includes(data.error_strategy)) {
		data.error_strategy = 'none'
	}

	if (!Array.isArray(data.default_value)) {
		data.default_value = []
	}

	if (typeof data.fail_branch_node_id !== 'string') {
		data.fail_branch_node_id = ''
	}

	return value
}

export const useSetterModel = <T>(
	props: { data: T },
	emit: (event: 'update', value: T) => void
): Ref<T> => {
	const formData = ref<T>(ensureRuntimeDefaults(cloneDeep(props.data))) as Ref<T>

	watch(
		() => props.data,
		(newVal) => {
			if (Object.is(newVal, formData.value)) {
				return
			}

			const nextValue = ensureRuntimeDefaults(cloneDeep(newVal))
			if (!isEqual(nextValue, formData.value)) {
				formData.value = nextValue
			}
		},
		{ deep: true, immediate: true }
	)

	watch(
		formData,
		(newVal) => {
			if (Object.is(newVal, props.data)) {
				return
			}

			if (!isEqual(newVal, props.data)) {
				emit('update', cloneDeep(newVal))
			}
		},
		{ deep: true }
	)

	return formData
}
