/**
 * Generic entity types composable.
 *
 * Replaces useComponentTypes, usePieceTypes, useProductTypes which were
 * 95%+ identical (only the category string and labels differed).
 */

import { ref, type Ref } from 'vue'
import { useToast } from './useToast'
import { useCustomFieldNameSuggestions } from './useCustomFieldNameSuggestions'
import { humanizeError } from '~/shared/utils/errorMessages'
import {
  listModelTypes,
  createModelType,
  updateModelType,
  deleteModelType,
  type ModelType,
  type ModelCategory,
} from '~/services/modelTypes'

export interface EntityType extends ModelType {
  description?: string | null
}

interface EntityTypePayload {
  name: string
  code?: string
  description?: string | null
  notes?: string | null
  structure?: any
}

interface EntityTypeResult {
  success: boolean
  data?: EntityType | EntityType[]
  error?: string
}

interface EntityTypeConfig {
  category: ModelCategory
  label: string // e.g. 'composant', 'pièce', 'produit'
}

const generateCodeFromName = (name: string): string => {
  return (name || '')
    .normalize('NFD')
    .replace(/[\u0300-\u036F]/g, '')
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '')
    .replace(/-+/g, '-') || 'type'
}

// Shared state per category (module-level singletons)
const stateByCategory: Record<string, { types: Ref<EntityType[]>; loading: Ref<boolean>; loaded: Ref<boolean> }> = {}

function getOrCreateState(category: ModelCategory) {
  if (!stateByCategory[category]) {
    stateByCategory[category] = {
      types: ref<EntityType[]>([]),
      loading: ref(false),
      loaded: ref(false),
    }
  }
  return stateByCategory[category]
}

/**
 * Marks the cache for a given category as stale.
 * Next call to `loadTypes()` (without `force`) will refetch from the API.
 * Safe to call from event handlers (no setup context required).
 */
export function invalidateEntityTypeCache(category: ModelCategory) {
  const state = stateByCategory[category]
  if (state) {
    state.loaded.value = false
  }
}

export function useEntityTypes(config: EntityTypeConfig) {
  const { category, label } = config
  const { showSuccess, showError } = useToast()
  const { invalidate: invalidateCustomFieldNames } = useCustomFieldNameSuggestions()
  const state = getOrCreateState(category)

  const normalizeItem = (item: ModelType): EntityType => ({
    ...item,
    description: item.description ?? item.notes ?? null,
  })

  const loadTypes = async (options: { force?: boolean } = {}): Promise<EntityTypeResult> => {
    if (!options.force && state.loaded.value) {
      return { success: true, data: state.types.value }
    }
    state.loading.value = true
    try {
      const data = await listModelTypes({
        category,
        sort: 'name',
        dir: 'asc',
        limit: 200,
      })
      state.types.value = data.items.map(normalizeItem)
      state.loaded.value = true
      return { success: true, data: state.types.value }
    } catch (error) {
      const err = error as Error & { message?: string }
      const message = humanizeError(err?.message)
      showError(`Impossible de charger les types de ${label}.`)
      return { success: false, error: message }
    } finally {
      state.loading.value = false
    }
  }

  const createType = async (payload: EntityTypePayload): Promise<EntityTypeResult> => {
    state.loading.value = true
    try {
      const data = await createModelType({
        name: payload.name,
        code: payload.code || generateCodeFromName(payload.name),
        category,
        notes: payload.description ?? payload.notes ?? undefined,
        description: payload.description ?? undefined,
        structure: payload.structure ?? undefined,
      })
      const normalized = normalizeItem(data)
      state.types.value.push(normalized)
      invalidateCustomFieldNames()
      showSuccess(`Type de ${label} "${data.name}" créé`)
      return { success: true, data: normalized }
    } catch (error) {
      const err = error as Error & { data?: { error?: string; message?: string }; message?: string }
      const raw = err?.data?.error || err?.data?.message || err?.message
      const message = humanizeError(raw)
      showError(`Impossible de créer le type de ${label} : ${message}`)
      return { success: false, error: message }
    } finally {
      state.loading.value = false
    }
  }

  const updateType = async (id: string, payload: EntityTypePayload): Promise<EntityTypeResult> => {
    state.loading.value = true
    try {
      const data = await updateModelType(id, {
        name: payload.name,
        description: payload.description ?? undefined,
        notes: payload.notes ?? undefined,
        code: payload.code,
        structure: payload.structure ?? undefined,
      })
      const normalized = normalizeItem(data)
      const index = state.types.value.findIndex((t) => t.id === id)
      if (index !== -1) state.types.value[index] = normalized
      invalidateCustomFieldNames()
      showSuccess(`Type de ${label} "${data.name}" mis à jour`)
      return { success: true, data: normalized }
    } catch (error) {
      const err = error as Error & { data?: { error?: string; message?: string }; message?: string }
      const raw = err?.data?.error || err?.data?.message || err?.message
      const message = humanizeError(raw)
      showError(`Impossible de mettre à jour le type de ${label} : ${message}`)
      return { success: false, error: message }
    } finally {
      state.loading.value = false
    }
  }

  const deleteType = async (id: string): Promise<EntityTypeResult> => {
    state.loading.value = true
    try {
      await deleteModelType(id)
      state.types.value = state.types.value.filter((t) => t.id !== id)
      showSuccess(`Type de ${label} supprimé`)
      return { success: true }
    } catch (error) {
      const err = error as Error & { data?: { error?: string; message?: string }; message?: string }
      const raw = err?.data?.error || err?.data?.message || err?.message
      const message = humanizeError(raw)
      showError(`Impossible de supprimer le type de ${label} : ${message}`)
      return { success: false, error: message }
    } finally {
      state.loading.value = false
    }
  }

  return {
    types: state.types,
    loading: state.loading,
    loadTypes,
    createType,
    updateType,
    deleteType,
  }
}
