import { watch, type Ref } from 'vue'
import {
  buildDimensionString,
  createDimensionWatcher,
  createStyleWatcher,
} from '@/utils/styleUtils.ts'
import type { FormBuilderStore } from '@/utils/styleUtils.ts'

export type StoreStyleWatcherEntry = {
  ref: Ref<unknown>
  storePath: string
  syncPaths: string[]
}

export type StoreDimensionWatcherEntry = {
  valueRef: Ref<number | null>
  unitRef: Ref<string>
  storePath: string
  syncPaths: string[]
}

export type CallbackStyleWatcherEntry = {
  watchRef: Ref<string>
  getCurrentValue: () => string | undefined
  onChange: () => void
}

export type CallbackDimensionWatcherEntry = {
  valueRef: Ref<number | null>
  unitRef: Ref<string>
  getCurrentValue: () => string | undefined
  onChange: () => void
}

export const registerDeferredWatchGroup = (
  sources: ReadonlyArray<Ref<unknown>>,
  isSyncingFromStore: Ref<boolean>,
  onChange: () => void,
) => {
  watch(sources, () => {
    if (isSyncingFromStore.value) return
    setTimeout(() => {
      onChange()
    }, 0)
  })
}

export const registerStoreStyleWatchers = (
  entries: StoreStyleWatcherEntry[],
  formBuilderStore: FormBuilderStore,
  isSyncingFromStore: Ref<boolean>,
) => {
  entries.forEach((entry) => {
    createStyleWatcher({
      ref: entry.ref,
      storePath: entry.storePath,
      syncPaths: entry.syncPaths,
      formBuilderStore,
      isSyncingFromStore,
    })
  })
}

export const registerStoreDimensionWatchers = (
  entries: StoreDimensionWatcherEntry[],
  formBuilderStore: FormBuilderStore,
  isSyncingFromStore: Ref<boolean>,
) => {
  entries.forEach((entry) => {
    createDimensionWatcher(
      entry.valueRef as unknown as Ref<number>,
      entry.unitRef,
      entry.storePath,
      entry.syncPaths,
      formBuilderStore,
      isSyncingFromStore,
    )
  })
}

export const registerCallbackStyleWatchers = (
  entries: CallbackStyleWatcherEntry[],
  isSyncingFromStore: Ref<boolean>,
) => {
  entries.forEach((entry) => {
    watch(entry.watchRef, (newValue) => {
      if (isSyncingFromStore.value) return
      setTimeout(() => {
        if (newValue !== entry.getCurrentValue()) {
          entry.onChange()
        }
      }, 0)
    })
  })
}

export const registerCallbackDimensionWatchers = (
  entries: CallbackDimensionWatcherEntry[],
  isSyncingFromStore: Ref<boolean>,
) => {
  entries.forEach((entry) => {
    watch([entry.valueRef, entry.unitRef], () => {
      if (isSyncingFromStore.value) return
      setTimeout(() => {
        const currentValue = entry.getCurrentValue()
        const newValue = buildDimensionString(entry.valueRef.value, entry.unitRef.value)
        if (newValue !== '' && newValue !== currentValue) {
          entry.onChange()
        }
      }, 0)
    })
  })
}
