import { computed, inject, onMounted, reactive, ref } from 'vue'
import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query'
import { useRoute, useRouter } from 'vue-router'
import { isKbxProblem, type KbxProblem, type KbxSelectionState } from '@kbx/contracts'
import { toKbxBulkSelectionRequest } from '@kbx/ui'
import { orderApi, type OrderBulkFilter, type OrderSearchFilter } from './orderApi'
import { kbxTelemetry, startKbxTask } from '../../../telemetry/kbxTelemetryClient'
import { orderListScreen } from './order-list.definition'
import { KbxScreenPreferenceScopeKey, loadScreenPreference, saveScreenPreference } from '../../../../preferences/screenPreferenceStore'
import { kbxStatusCatalog, normalizeKbxStatusValue } from '../../../../registry/statusCatalog'

function todayIso() { return new Date().toISOString().slice(0, 10) }

export function useOrderSearch() {
  const router = useRouter()
  const route = useRoute()
  const queryClient = useQueryClient()
  const selectionState = ref<KbxSelectionState<string>>({ mode:'explicit', selectedIds:[] })
  const preferenceScope = inject(KbxScreenPreferenceScopeKey, ref(''))
  const rememberSearch = ref(false)
  const savedSearchDefaults = ref<Record<string, unknown> | undefined>()
  const preferenceNotice = ref('')
  const problem = ref<KbxProblem | null>(null)
  const failedCommand = ref<'ship' | null>(null)

  const search = reactive<OrderSearchFilter>({
    from: todayIso(), to: todayIso(), channelId: null, status: null,
    exceptionOnly: false, keyword: '', page: 1, pageSize: 100,
  })
  const appliedSearch = ref<OrderSearchFilter>({ ...search })

  function firstQueryValue(value: unknown) {
    return Array.isArray(value) ? value[0] : value
  }

  function hydrateSearchFromRoute() {
    let contextual = false
    const from = String(firstQueryValue(route.query.from) ?? '')
    const to = String(firstQueryValue(route.query.to) ?? '')
    const status = String(firstQueryValue(route.query.status) ?? '')
    const exceptionOnly = String(firstQueryValue(route.query.exceptionOnly) ?? '')
    const keyword = String(firstQueryValue(route.query.keyword) ?? '')
    const channelId = String(firstQueryValue(route.query.channelId) ?? '')

    if (/^\d{4}-\d{2}-\d{2}$/.test(from)) { search.from = from; contextual = true }
    if (/^\d{4}-\d{2}-\d{2}$/.test(to)) { search.to = to; contextual = true }
    const canonicalStatus = normalizeKbxStatusValue(kbxStatusCatalog.orderShipment, status)
    if (canonicalStatus) { search.status = canonicalStatus; contextual = true }
    if (exceptionOnly === 'true') { search.exceptionOnly = true; contextual = true }
    if (keyword) { search.keyword = keyword.slice(0, 100); contextual = true }
    if (channelId) { search.channelId = channelId.slice(0, 64); contextual = true }
    return contextual
  }


  function safePersistableSearch() {
    return {
      from: /^\d{4}-\d{2}-\d{2}$/.test(search.from) ? search.from : todayIso(),
      to: /^\d{4}-\d{2}-\d{2}$/.test(search.to) ? search.to : todayIso(),
      channelId: typeof search.channelId === 'string' ? search.channelId.slice(0, 64) : null,
      status: normalizeKbxStatusValue(kbxStatusCatalog.orderShipment, search.status),
      exceptionOnly: Boolean(search.exceptionOnly),
    }
  }

  function applySafeSearchDefaults(value: Record<string, unknown> | undefined) {
    if (!value) return false
    let applied = false
    if (typeof value.from === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(value.from)) { search.from = value.from; applied = true }
    if (typeof value.to === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(value.to)) { search.to = value.to; applied = true }
    if (typeof value.channelId === 'string' && value.channelId.length <= 64) { search.channelId = value.channelId || null; applied = true }
    if (value.channelId === null) { search.channelId = null; applied = true }
    const canonicalStatus = normalizeKbxStatusValue(kbxStatusCatalog.orderShipment, value.status)
    if (canonicalStatus) { search.status = canonicalStatus; applied = true }
    if (value.status === null) { search.status = null; applied = true }
    if (typeof value.exceptionOnly === 'boolean') { search.exceptionOnly = value.exceptionOnly; applied = true }
    // Free-text keyword is intentionally never restored from local preference storage.
    search.keyword = ''
    return applied
  }

  function persistPreference(message: string) {
    const scope = preferenceScope.value
    if (!scope) return false
    const saved = saveScreenPreference(scope, {
      screenId: orderListScreen.id,
      screenVersion: orderListScreen.version,
      rememberSearch: rememberSearch.value,
      searchDefaults: savedSearchDefaults.value,
    })
    preferenceNotice.value = saved ? message : '개인화 설정을 저장하지 못했습니다. 현재 업무는 계속 사용할 수 있습니다.'
    return saved
  }

  function setRememberSearch(value: boolean) {
    rememberSearch.value = value
    if (value) savedSearchDefaults.value = safePersistableSearch()
    persistPreference(value ? '마지막 조회조건 기억을 켰습니다. 자유검색어는 저장하지 않습니다.' : '마지막 조회조건 기억을 껐습니다.')
  }

  function saveCurrentSearchDefaults() {
    savedSearchDefaults.value = safePersistableSearch()
    persistPreference('현재 조회조건을 이 화면의 기본조건으로 저장했습니다. 자유검색어는 저장하지 않습니다.')
  }

  const query = useQuery({
    queryKey: computed(() => ['oms', 'orders', appliedSearch.value]),
    queryFn: () => orderApi.search({ ...appliedSearch.value }),
    enabled: false,
  })

  const shipMutation = useMutation({
    mutationFn: (selection: ReturnType<typeof currentBulkSelection>) => orderApi.ship(selection),
    onSuccess: async () => {
      selectionState.value = { mode:'explicit', selectedIds:[] }
      await queryClient.invalidateQueries({ queryKey: ['oms', 'orders'] })
      await query.refetch()
    },
  })

  const selectionCount = computed(() => selectionState.value.mode === 'all-filtered'
    ? Math.max((query.data.value?.totalCount ?? 0) - (selectionState.value.excludedIds?.length ?? 0), 0)
    : selectionState.value.selectedIds.length)

  function currentBulkFilter(): OrderBulkFilter {
    return {
      from: appliedSearch.value.from, to: appliedSearch.value.to, channelId: appliedSearch.value.channelId,
      status: appliedSearch.value.status, exceptionOnly: appliedSearch.value.exceptionOnly, keyword: appliedSearch.value.keyword,
    }
  }

  function currentBulkSelection() {
    return toKbxBulkSelectionRequest(selectionState.value, currentBulkFilter())
  }

  async function executeSearch() {
    problem.value = null
    failedCommand.value = null
    const started=performance.now();selectionState.value={mode:'explicit',selectedIds:[]};appliedSearch.value={...search}
    kbxTelemetry.track('command.execute',{screenId:orderListScreen.id,screenVersion:orderListScreen.version,attributes:{commandId:'search',operationKind:'query'}})
    kbxTelemetry.track('search.execute',{screenId:orderListScreen.id,screenVersion:orderListScreen.version,attributes:{resultBucket:'requested'}})
    await query.refetch()
    if (rememberSearch.value) { savedSearchDefaults.value = safePersistableSearch(); persistPreference('마지막 조회조건을 기억했습니다. 자유검색어는 저장하지 않습니다.') }
    kbxTelemetry.track('command.succeeded',{screenId:orderListScreen.id,screenVersion:orderListScreen.version,durationMs:Math.round(performance.now()-started),attributes:{commandId:'search',operationKind:'query'}})
  }


  async function resetAndSearch() {
    Object.assign(search, { from:todayIso(), to:todayIso(), channelId:null, status:null, exceptionOnly:false, keyword:'', page:1, pageSize:100 })
    await executeSearch()
  }

  onMounted(() => {
    const contextual = hydrateSearchFromRoute()
    const preference = loadScreenPreference(preferenceScope.value, orderListScreen.id, orderListScreen.version)
    rememberSearch.value = Boolean(preference?.rememberSearch)
    savedSearchDefaults.value = preference?.searchDefaults
    if (!contextual && savedSearchDefaults.value) applySafeSearchDefaults(savedSearchDefaults.value)
    if (contextual) void executeSearch()
  })

  async function executeCommand(commandId: string) {
    const handlers: Record<string, () => unknown | Promise<unknown>> = {
      search: executeSearch,
      new: () => router.push({ name: 'oms-order-new' }),
      ship: async () => {
        const task=startKbxTask(orderListScreen.id,orderListScreen.version,'ship-orders');task.interaction('bulk-command','ship')
        kbxTelemetry.track('grid.bulk_action',{screenId:orderListScreen.id,screenVersion:orderListScreen.version,taskSessionId:task.id,attributes:{commandId:'ship',countBucket:selectionCount.value<10?'1-9':selectionCount.value<100?'10-99':'100+',selectionMode:selectionState.value.mode}})
        try{await shipMutation.mutateAsync(currentBulkSelection());problem.value=null;failedCommand.value=null;task.complete('success')}catch(error){task.abandon('failed');if(isKbxProblem(error)){problem.value=error;failedCommand.value='ship';return}throw error}
      },
    }
    return handlers[commandId]?.()
  }


  async function retryProblem() {
    const action = failedCommand.value
    problem.value = null
    failedCommand.value = null
    if (action === 'ship' && selectionCount.value > 0) return executeCommand('ship')
  }

  function dismissProblem() {
    problem.value = null
    failedCommand.value = null
  }

  return {
    search,
    appliedSearch,
    rows: computed(() => query.data.value?.items ?? []),
    result: computed(() => query.data.value),
    loading: computed(() => query.isFetching.value),
    error: computed(() => query.error.value),
    selectionState,
    selectionCount,
    rememberSearch,
    preferenceNotice,
    problem,
    setRememberSearch,
    saveCurrentSearchDefaults,
    executeSearch,
    resetAndSearch,
    executeCommand,
    retryProblem,
    dismissProblem,
  }
}
