'use client'
import type { ComboboxChangeEventDetails } from '@langgenius/dify-ui/combobox'
import type { ParentMode, SimpleDocumentDetail } from '@/models/datasets'
import { cn } from '@langgenius/dify-ui/cn'
import {
  Combobox,
  ComboboxEmpty,
  ComboboxInput,
  ComboboxInputGroup,
  ComboboxPopup,
  ComboboxPortal,
  ComboboxPositioner,
  ComboboxStatus,
  ComboboxTrigger,
  ComboboxValue,
} from '@langgenius/dify-ui/combobox'
import { useDebounce } from 'ahooks'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import Loading from '@/app/components/base/loading'
import { ChunkingMode } from '@/models/datasets'
import { useDocumentList } from '@/service/knowledge/use-document'
import FileIcon from '../document-file-icon'
import DocumentList from './document-list'

type Props = Readonly<{
  datasetId: string
  value?: SimpleDocumentDetail | null
  parentMode?: ParentMode
  onChange: (value: SimpleDocumentDetail) => void
}>

function getDocumentLabel(document: SimpleDocumentDetail) {
  return document.name
}

function getDocumentValue(document: SimpleDocumentDetail) {
  return document.id
}

function isSameDocument(item: SimpleDocumentDetail, value: SimpleDocumentDetail) {
  return item.id === value.id
}

function getDocumentExtension(document?: SimpleDocumentDetail | null) {
  if (!document) return ''

  const detailExtension = document.data_source_detail_dict?.upload_file?.extension
  if (detailExtension) return detailExtension

  const dataSourceInfo = document.data_source_info
  if (dataSourceInfo && 'upload_file' in dataSourceInfo) return dataSourceInfo.upload_file.extension

  return ''
}

function DocumentPickerTriggerValue({
  document,
  parentMode,
}: {
  document?: SimpleDocumentDetail | null
  parentMode?: ParentMode
}) {
  const { t } = useTranslation()
  const isGeneralMode = document?.doc_form === ChunkingMode.text
  const isParentChild = document?.doc_form === ChunkingMode.parentChild
  const isQAMode = document?.doc_form === ChunkingMode.qa
  const parentModeLabel = (() => {
    if (!parentMode) return '--'
    return parentMode === 'paragraph'
      ? t(($) => $['parentMode.paragraph'], { ns: 'dataset' })
      : t(($) => $['parentMode.fullDoc'], { ns: 'dataset' })
  })()

  return (
    <span className="flex min-w-0 items-center gap-1.5">
      <FileIcon name={document?.name} extension={getDocumentExtension(document)} size="xl" />
      <span className="flex min-w-0 flex-col items-start">
        <span className="flex max-w-full min-w-0 items-center gap-1">
          <span className="max-w-70 min-w-0 truncate system-md-semibold text-text-primary">
            {document?.name || '--'}
          </span>
          <span
            className="i-ri-arrow-down-s-line size-4 shrink-0 text-text-primary"
            aria-hidden="true"
          />
        </span>
        <span className="flex h-3 max-w-75 items-center gap-0.5 text-text-tertiary">
          <span
            className={cn(
              'size-3 shrink-0',
              isParentChild
                ? 'i-custom-vender-knowledge-parent-child-chunk'
                : 'i-custom-vender-knowledge-general-chunk',
            )}
            aria-hidden="true"
          />
          <span className={cn('truncate system-2xs-medium-uppercase', isParentChild && 'mt-0.5')}>
            {isGeneralMode && t(($) => $['chunkingMode.general'], { ns: 'dataset' })}
            {isQAMode && t(($) => $['chunkingMode.qa'], { ns: 'dataset' })}
            {isParentChild &&
              `${t(($) => $['chunkingMode.parentChild'], { ns: 'dataset' })} · ${parentModeLabel}`}
          </span>
        </span>
      </span>
    </span>
  )
}

export function DocumentPicker({ datasetId, value, parentMode, onChange }: Props) {
  const { t } = useTranslation()
  const [searchValue, setSearchValue] = useState('')
  const debouncedSearchValue = useDebounce(searchValue, { wait: 500 })

  const { data } = useDocumentList({
    datasetId,
    query: {
      keyword: debouncedSearchValue,
      page: 1,
      limit: 20,
    },
  })
  const documentsList = data?.data ?? []

  const handleInputValueChange = (inputValue: string, details: ComboboxChangeEventDetails) => {
    if (details.reason !== 'item-press') setSearchValue(inputValue)
  }

  const handleOpenChange = (nextOpen: boolean) => {
    if (!nextOpen) setSearchValue('')
  }

  const handleDocumentChange = (document: SimpleDocumentDetail | null) => {
    if (!document) return

    onChange(document)
    setSearchValue('')
  }

  return (
    <Combobox<SimpleDocumentDetail>
      items={documentsList}
      value={value ?? null}
      inputValue={searchValue}
      onOpenChange={handleOpenChange}
      onInputValueChange={handleInputValueChange}
      onValueChange={handleDocumentChange}
      isItemEqualToValue={isSameDocument}
      itemToStringLabel={getDocumentLabel}
      itemToStringValue={getDocumentValue}
      filter={null}
    >
      <ComboboxTrigger
        aria-label={value?.name || t(($) => $['operation.search'], { ns: 'common' })}
        icon={false}
        className={cn(
          'ml-1 flex size-auto rounded-lg border-0 bg-transparent px-2 py-1 hover:bg-state-base-hover focus-visible:bg-state-base-hover data-popup-open:bg-state-base-hover',
        )}
      >
        <ComboboxValue<SimpleDocumentDetail>>
          {(document) => <DocumentPickerTriggerValue document={document} parentMode={parentMode} />}
        </ComboboxValue>
      </ComboboxTrigger>
      <ComboboxPortal>
        <ComboboxPositioner placement="bottom-start" sideOffset={0}>
          <ComboboxPopup
            aria-label={t(($) => $['operation.search'], { ns: 'common' })}
            className="w-90 rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-2 shadow-lg backdrop-blur-[5px]"
          >
            <ComboboxInputGroup className="h-8 min-h-8 px-2">
              <span
                className="mr-0.5 i-ri-search-line size-4 shrink-0 text-text-tertiary"
                aria-hidden="true"
              />
              <ComboboxInput
                aria-label={t(($) => $['operation.search'], { ns: 'common' })}
                placeholder={t(($) => $['operation.search'], { ns: 'common' })}
                className="block h-4.5 grow px-1 py-0 text-[13px] text-text-primary"
              />
            </ComboboxInputGroup>
            <DocumentList className="mt-2 data-empty:mt-0" />
            <ComboboxEmpty className="p-0">
              {data && (
                <div className="mt-2 flex h-25 w-full items-center justify-center px-3 py-2 system-sm-regular text-text-tertiary">
                  {t(($) => $.noData, { ns: 'common' })}
                </div>
              )}
            </ComboboxEmpty>
            <ComboboxStatus
              className={cn(!data ? 'mt-2 flex h-25 w-full items-center justify-center' : 'h-0')}
            >
              {!data && (
                <>
                  <span className="sr-only">{t(($) => $.loading, { ns: 'common' })}</span>
                  <div className="w-full" aria-hidden="true">
                    <Loading />
                  </div>
                </>
              )}
            </ComboboxStatus>
          </ComboboxPopup>
        </ComboboxPositioner>
      </ComboboxPortal>
    </Combobox>
  )
}
