import { ref, computed, watch } from 'vue'
import type {
  LoraPoolConfig,
  BaseModelOption,
  TagOption,
  FolderTreeNode,
  LoraItem,
  ComponentWidget
} from './types'
import { useLoraPoolApi } from './useLoraPoolApi'

export function useLoraPoolState(widget: ComponentWidget<LoraPoolConfig>) {
  const api = useLoraPoolApi()

  // Flag to prevent infinite loops during config restoration
  // callback → restoreFromConfig → watch → refreshPreview → buildConfig → widget.value = config → callback → ...
  let isRestoring = false

  // Filter state
  const selectedBaseModels = ref<string[]>([])
  const includeTags = ref<string[]>([])
  const excludeTags = ref<string[]>([])
  const includeFolders = ref<string[]>([])
  const excludeFolders = ref<string[]>([])
  const noCreditRequired = ref(false)
  const allowSelling = ref(false)
  const includePatterns = ref<string[]>([])
  const excludePatterns = ref<string[]>([])
  const useRegex = ref(false)

  // Available options from API
  const availableBaseModels = ref<BaseModelOption[]>([])
  const availableTags = ref<TagOption[]>([])
  const folderTree = ref<FolderTreeNode[]>([])

  // Preview state
  const previewItems = ref<LoraItem[]>([])
  const matchCount = ref(0)
  const isLoading = computed(() => api.isLoading.value)

  // Build config from current state
  const buildConfig = (): LoraPoolConfig => {
    const config: LoraPoolConfig = {
      version: 2,
      filters: {
        baseModels: selectedBaseModels.value,
        tags: {
          include: includeTags.value,
          exclude: excludeTags.value
        },
        folders: {
          include: includeFolders.value,
          exclude: excludeFolders.value
        },
        license: {
          noCreditRequired: noCreditRequired.value,
          allowSelling: allowSelling.value
        },
        namePatterns: {
          include: includePatterns.value,
          exclude: excludePatterns.value,
          useRegex: useRegex.value
        }
      },
      preview: {
        matchCount: matchCount.value,
        lastUpdated: Date.now()
      }
    }

    // Update widget value (this triggers callback for UI sync)
    // Skip during restoration to prevent infinite loops:
    // callback → restoreFromConfig → watch → refreshPreview → buildConfig → widget.value = config → callback → ...
    if (!isRestoring) {
      widget.value = config
    }
    return config
  }

  // Restore state from config
  const restoreFromConfig = (config: LoraPoolConfig) => {
    // Set flag to prevent buildConfig from triggering widget.value updates during restoration
    // This breaks the infinite loop: callback → restoreFromConfig → watch → refreshPreview → buildConfig → widget.value = config → callback
    isRestoring = true

    try {
      if (!config?.filters) return

      const { filters, preview } = config

      // Helper to update ref only if value changed
      const updateIfChanged = <T>(refValue: { value: T }, newValue: T) => {
        if (JSON.stringify(refValue.value) !== JSON.stringify(newValue)) {
          refValue.value = newValue
        }
      }

      updateIfChanged(selectedBaseModels, filters.baseModels || [])
      updateIfChanged(includeTags, filters.tags?.include || [])
      updateIfChanged(excludeTags, filters.tags?.exclude || [])
      updateIfChanged(includeFolders, filters.folders?.include || [])
      updateIfChanged(excludeFolders, filters.folders?.exclude || [])
      updateIfChanged(noCreditRequired, filters.license?.noCreditRequired ?? false)
      updateIfChanged(allowSelling, filters.license?.allowSelling ?? false)
      updateIfChanged(includePatterns, filters.namePatterns?.include || [])
      updateIfChanged(excludePatterns, filters.namePatterns?.exclude || [])
      updateIfChanged(useRegex, filters.namePatterns?.useRegex ?? false)

      // matchCount doesn't trigger watchers, so direct assignment is fine
      matchCount.value = preview?.matchCount || 0
    } finally {
      isRestoring = false
    }
  }

  // Fetch filter options from API
  const fetchFilterOptions = async () => {
    const [baseModels, tags, folders] = await Promise.all([
      api.fetchBaseModels(),
      api.fetchTags(),
      api.fetchFolderTree()
    ])

    availableBaseModels.value = baseModels
    availableTags.value = tags
    folderTree.value = folders
  }

  // Refresh preview with current filters
  const refreshPreview = async () => {
    const result = await api.fetchLoras({
      baseModels: selectedBaseModels.value,
      tagsInclude: includeTags.value,
      tagsExclude: excludeTags.value,
      foldersInclude: includeFolders.value,
      foldersExclude: excludeFolders.value,
      noCreditRequired: noCreditRequired.value || undefined,
      allowSelling: allowSelling.value || undefined,
      namePatternsInclude: includePatterns.value,
      namePatternsExclude: excludePatterns.value,
      namePatternsUseRegex: useRegex.value,
      pageSize: 6
    })

    previewItems.value = result.items
    matchCount.value = result.total
    buildConfig()
  }

  // Debounced filter change handler
  let filterTimeout: ReturnType<typeof setTimeout> | null = null
  const onFilterChange = () => {
    if (filterTimeout) clearTimeout(filterTimeout)
    filterTimeout = setTimeout(() => {
      refreshPreview()
    }, 300)
  }

  // Watch all filter changes
  watch([
    selectedBaseModels,
    includeTags,
    excludeTags,
    includeFolders,
    excludeFolders,
    noCreditRequired,
    allowSelling,
    includePatterns,
    excludePatterns,
    useRegex
  ], onFilterChange, { deep: true })

  return {
    // Filter state
    selectedBaseModels,
    includeTags,
    excludeTags,
    includeFolders,
    excludeFolders,
    noCreditRequired,
    allowSelling,
    includePatterns,
    excludePatterns,
    useRegex,

    // Available options
    availableBaseModels,
    availableTags,
    folderTree,

    // Preview state
    previewItems,
    matchCount,
    isLoading,

    // Actions
    buildConfig,
    restoreFromConfig,
    fetchFilterOptions,
    refreshPreview
  }
}

export type LoraPoolStateReturn = ReturnType<typeof useLoraPoolState>
