<template>
  <div class="space-y-6">
    <StructureNodeEditor
      :node="localStructure"
      :depth="0"
      :component-types="availableComponentTypes"
      :piece-types="availablePieceTypes"
      :lock-type="lockRootType"
      :locked-type-label="displayedRootTypeLabel"
      :allow-subcomponents="allowSubcomponents"
      is-root
    />
  </div>
</template>

<script setup lang="ts">
import { reactive, watch, computed, onMounted, ref } from 'vue'
import StructureNodeEditor from '~/components/StructureNodeEditor.vue'
import {
  defaultStructure,
  hydrateStructureForEditor,
  cloneStructure,
} from '~/shared/modelUtils'
import { usePieceTypes } from '~/composables/usePieceTypes'
import { useComponentTypes } from '~/composables/useComponentTypes'
import type { ComponentModelStructure } from '~/shared/types/inventory'

defineOptions({ name: 'ComponentModelStructureEditor' })

const props = defineProps({
  modelValue: {
    type: Object,
    default: () => defaultStructure(),
  },
  rootTypeId: {
    type: String,
    default: '',
  },
  rootTypeLabel: {
    type: String,
    default: '',
  },
  lockRootType: {
    type: Boolean,
    default: false,
  },
  allowSubcomponents: {
    type: Boolean,
    default: true,
  },
})

const emit = defineEmits(['update:modelValue'])

const localStructure = reactive<ComponentModelStructure>(hydrateStructureForEditor(props.modelValue))
const previousLockedLabel = ref(props.rootTypeLabel || '')

const { pieceTypes, loadPieceTypes } = usePieceTypes()
const { componentTypes, loadComponentTypes } = useComponentTypes()

const availablePieceTypes = computed(() => pieceTypes.value ?? [])
const availableComponentTypes = computed(() => componentTypes.value ?? [])
const allowSubcomponents = computed(() => props.allowSubcomponents !== false)

const fallbackRootTypeLabel = computed(() => {
  if (!props.rootTypeId) {
    return ''
  }
  const match = availableComponentTypes.value.find((type) => type?.id === props.rootTypeId)
  return match?.name || ''
})

const displayedRootTypeLabel = computed(() => props.rootTypeLabel || fallbackRootTypeLabel.value)

const syncRootType = () => {
  if (!props.lockRootType) {
    previousLockedLabel.value = props.rootTypeLabel || ''
    return
  }

  const newTypeId = props.rootTypeId || ''
  const newLabel = displayedRootTypeLabel.value

  localStructure.typeComposantId = newTypeId
  localStructure.typeComposantLabel = newLabel

  const match = availableComponentTypes.value.find((type) => type?.id === newTypeId)
  if (match?.code) {
    localStructure.familyCode = match.code
  }

  const previousLabel = previousLockedLabel.value
  if (!localStructure.alias || localStructure.alias === previousLabel || localStructure.alias === '') {
    localStructure.alias = newLabel || localStructure.alias
  }

  previousLockedLabel.value = newLabel
}

let lastEmitted = JSON.stringify(cloneStructure(props.modelValue))

const syncFromProps = (value: any) => {
  const hydrated = hydrateStructureForEditor(value)
  localStructure.customFields = hydrated.customFields
  localStructure.pieces = hydrated.pieces
  localStructure.subcomponents = hydrated.subcomponents
  localStructure.typeComposantId = hydrated.typeComposantId
  localStructure.typeComposantLabel = hydrated.typeComposantLabel
  localStructure.modelId = hydrated.modelId
  localStructure.familyCode = hydrated.familyCode
  localStructure.alias = hydrated.alias
  lastEmitted = JSON.stringify(cloneStructure(value))
  syncRootType()
}

watch(
  () => props.modelValue,
  (value) => {
    syncFromProps(value)
  },
  { deep: true }
)

watch(
  () => [props.rootTypeId, props.rootTypeLabel, props.lockRootType],
  () => {
    syncRootType()
  },
  { immediate: true }
)

watch(
  availableComponentTypes,
  () => {
    syncRootType()
  }
)

watch(
  localStructure,
  (value) => {
    const payload = cloneStructure(value)
    const serialized = JSON.stringify(payload)
    if (serialized !== lastEmitted) {
      lastEmitted = serialized
      emit('update:modelValue', payload)
    }
  },
  { deep: true }
)

onMounted(async () => {
  const loaders: Promise<any>[] = []
  if (!availablePieceTypes.value.length) {
    loaders.push(loadPieceTypes())
  }
  if (!availableComponentTypes.value.length) {
    loaders.push(loadComponentTypes())
  }
  if (loaders.length) {
    await Promise.allSettled(loaders)
  }
  syncRootType()
})

watch(
  allowSubcomponents,
  (allowed) => {
    if (!allowed && Array.isArray(localStructure.subcomponents) && localStructure.subcomponents.length) {
      localStructure.subcomponents = []
    }
  },
  { immediate: true }
)
</script>
