'use client'
import type { FC } from 'react'
import type { DocumentDisplayStatus, FileItem, FullDocumentDetail } from '@/models/datasets'
import type { SegmentImportStatus } from '@/types/dataset'
import { cn } from '@langgenius/dify-ui/cn'
import { toast } from '@langgenius/dify-ui/toast'
import { useAtomValue } from 'jotai'
import * as React from 'react'
import { useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import Divider from '@/app/components/base/divider'
import FloatRightContainer from '@/app/components/base/float-right-container'
import Loading from '@/app/components/base/loading'
import Metadata from '@/app/components/datasets/metadata/metadata-document'
import { userProfileIdAtom } from '@/context/account-state'
import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail'
import { workspacePermissionKeysAtom } from '@/context/permission-state'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import { ChunkingMode, DisplayStatusList } from '@/models/datasets'
import { useRouter, useSearchParams } from '@/next/navigation'
import {
  useDocumentDetail,
  useDocumentMetadata,
  useInvalidDocumentList,
} from '@/service/knowledge/use-document'
import {
  useCheckSegmentBatchImportProgress,
  useChildSegmentListKey,
  useSegmentBatchImport,
  useSegmentListKey,
} from '@/service/knowledge/use-segment'
import { useInvalid } from '@/service/use-base'
import { segmentImportStatus } from '@/types/dataset'
import { getDatasetACLCapabilities } from '@/utils/permission'
import Operations from '../components/operations'
import StatusItem from '../status-item'
import BatchModal from './batch-modal'
import Completed from './completed'
import { DocumentContext } from './context'
import { DocumentTitle } from './document-title'
import Embedding from './embedding'
import { SegmentAdd } from './segment-add'
import style from './style.module.css'

type DocumentDetailProps = {
  datasetId: string
  documentId: string
}

const NON_TERMINAL_DISPLAY_STATUSES = new Set<(typeof DisplayStatusList)[number]>(
  DisplayStatusList.filter((s) => s === 'queuing' || s === 'indexing' || s === 'paused'),
)

const DocumentDetail: FC<DocumentDetailProps> = ({ datasetId, documentId }) => {
  const router = useRouter()
  const searchParams = useSearchParams()
  const { t } = useTranslation()

  const media = useBreakpoints()
  const isMobile = media === MediaType.mobile

  const dataset = useDatasetDetailContextWithSelector((s) => s.dataset)
  const currentUserId = useAtomValue(userProfileIdAtom)
  const workspacePermissionKeys = useAtomValue(workspacePermissionKeysAtom)
  const embeddingAvailable = !!dataset?.embedding_available
  const datasetACLCapabilities = useMemo(
    () =>
      getDatasetACLCapabilities(dataset?.permission_keys, {
        currentUserId,
        resourceMaintainer: dataset?.maintainer,
        workspacePermissionKeys,
      }),
    [dataset?.maintainer, dataset?.permission_keys, currentUserId, workspacePermissionKeys],
  )
  const canEditDocument = datasetACLCapabilities.canEdit
  const [showMetadata, setShowMetadata] = useState(!isMobile)
  const [newSegmentModalVisible, setNewSegmentModalVisible] = useState(false)
  const [batchModalVisible, setBatchModalVisible] = useState(false)
  const [importStatus, setImportStatus] = useState<SegmentImportStatus>()
  const showNewSegmentModal = () => setNewSegmentModalVisible(true)
  const showBatchModal = () => setBatchModalVisible(true)
  const hideBatchModal = () => setBatchModalVisible(false)
  const resetImportStatus = () => setImportStatus(undefined)

  const { mutateAsync: checkSegmentBatchImportProgress } = useCheckSegmentBatchImportProgress()
  const checkProcess = async (jobID: string) => {
    await checkSegmentBatchImportProgress(
      { jobID },
      {
        onSuccess: (res) => {
          setImportStatus(res.job_status)
          if (
            res.job_status === segmentImportStatus.waiting ||
            res.job_status === segmentImportStatus.processing
          )
            setTimeout(() => checkProcess(res.job_id), 2500)
          if (res.job_status === segmentImportStatus.error)
            toast.error(`${t(($) => $['list.batchModal.runError'], { ns: 'datasetDocuments' })}`)
        },
        onError: (e) => {
          const message = 'message' in e ? `: ${e.message}` : ''
          toast.error(
            `${t(($) => $['list.batchModal.runError'], { ns: 'datasetDocuments' })}${message}`,
          )
        },
      },
    )
  }

  const { mutateAsync: segmentBatchImport } = useSegmentBatchImport()
  const runBatch = async (csv: FileItem) => {
    await segmentBatchImport(
      {
        url: `/datasets/${datasetId}/documents/${documentId}/segments/batch_import`,
        body: { upload_file_id: csv.file.id! },
      },
      {
        onSuccess: (res) => {
          setImportStatus(res.job_status)
          checkProcess(res.job_id)
        },
        onError: (e) => {
          const message = 'message' in e ? `: ${e.message}` : ''
          toast.error(
            `${t(($) => $['list.batchModal.runError'], { ns: 'datasetDocuments' })}${message}`,
          )
        },
      },
    )
  }

  const {
    data: documentDetail,
    error,
    refetch: detailMutate,
  } = useDocumentDetail({
    datasetId,
    documentId,
    params: { metadata: 'without' },
    refetchInterval: (query) => {
      const status = query.state.data?.display_status
      if (!status || NON_TERMINAL_DISPLAY_STATUSES.has(status)) return 2500
      return false
    },
  })

  const { data: documentMetadata } = useDocumentMetadata({
    datasetId,
    documentId,
    params: { metadata: 'only' },
  })

  const backToPrev = useCallback(() => {
    const queryString = searchParams.toString()
    const backPath = `/datasets/${datasetId}/documents${queryString ? `?${queryString}` : ''}`
    router.push(backPath)
  }, [searchParams, datasetId, router])

  const isDetailLoading = !documentDetail && !error

  const embedding = NON_TERMINAL_DISPLAY_STATUSES.has(
    documentDetail?.display_status as DocumentDisplayStatus,
  )

  const invalidChunkList = useInvalid(useSegmentListKey)
  const invalidChildChunkList = useInvalid(useChildSegmentListKey)
  const invalidDocumentList = useInvalidDocumentList(datasetId)

  const handleOperate = useCallback(
    (operateName?: string) => {
      invalidDocumentList()
      if (operateName === 'delete') {
        backToPrev()
      } else {
        detailMutate()
        // If operation is not rename, refresh the chunk list after 5 seconds
        if (operateName) {
          setTimeout(() => {
            invalidChunkList()
            invalidChildChunkList()
          }, 5000)
        }
      }
    },
    [invalidDocumentList, backToPrev, detailMutate, invalidChunkList, invalidChildChunkList],
  )

  const parentMode = useMemo(() => {
    return (
      documentDetail?.document_process_rule?.rules?.parent_mode ||
      documentDetail?.dataset_process_rule?.rules?.parent_mode ||
      'paragraph'
    )
  }, [
    documentDetail?.document_process_rule?.rules?.parent_mode,
    documentDetail?.dataset_process_rule?.rules?.parent_mode,
  ])

  const isFullDocMode = useMemo(() => {
    const chunkMode = documentDetail?.doc_form
    return chunkMode === ChunkingMode.parentChild && parentMode === 'full-doc'
  }, [documentDetail?.doc_form, parentMode])

  const contextValue = useMemo(
    () => ({
      datasetId,
      documentId,
      docForm: documentDetail?.doc_form as ChunkingMode,
      parentMode,
    }),
    [datasetId, documentId, documentDetail?.doc_form, parentMode],
  )

  const statusDetail = useMemo(
    () => ({
      enabled: documentDetail?.enabled || false,
      archived: documentDetail?.archived || false,
      id: documentId,
    }),
    [documentDetail?.enabled, documentDetail?.archived, documentId],
  )

  const operationsDetail = useMemo(
    () => ({
      name: documentDetail?.name || '',
      enabled: documentDetail?.enabled || false,
      archived: documentDetail?.archived || false,
      id: documentId,
      data_source_type: documentDetail?.data_source_type || '',
      doc_form: documentDetail?.doc_form || '',
    }),
    [
      documentDetail?.name,
      documentDetail?.enabled,
      documentDetail?.archived,
      documentId,
      documentDetail?.data_source_type,
      documentDetail?.doc_form,
    ],
  )

  const docDetail = useMemo(
    () =>
      ({
        ...documentDetail,
        ...documentMetadata,
        doc_type: documentMetadata?.doc_type === 'others' ? '' : documentMetadata?.doc_type,
      }) as FullDocumentDetail,
    [documentDetail, documentMetadata],
  )

  const backButtonLabel = t(($) => $['operation.back'], { ns: 'common' })
  const metadataToggleLabel = `${
    showMetadata
      ? t(($) => $['operation.close'], { ns: 'common' })
      : t(($) => $['operation.view'], { ns: 'common' })
  } ${t(($) => $['metadata.title'], { ns: 'datasetDocuments' })}`

  return (
    <DocumentContext.Provider value={contextValue}>
      <div className="flex h-full flex-col bg-background-default">
        <div className="flex min-h-16 flex-wrap items-center justify-between border-b border-b-divider-subtle py-2.5 pr-4 pl-3">
          <button
            type="button"
            aria-label={backButtonLabel}
            title={backButtonLabel}
            onClick={backToPrev}
            className="flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-full border-none bg-transparent p-0 hover:bg-components-button-tertiary-bg focus-visible:ring-1 focus-visible:ring-components-input-border-active focus-visible:outline-hidden"
          >
            <span
              aria-hidden="true"
              className="i-ri-arrow-left-line size-4 text-components-button-ghost-text hover:text-text-tertiary"
            />
          </button>
          <DocumentTitle
            datasetId={datasetId}
            document={documentDetail}
            wrapperCls="mr-2"
            parentMode={parentMode}
          />
          <div className="flex flex-wrap items-center">
            {embeddingAvailable &&
              canEditDocument &&
              documentDetail &&
              !documentDetail.archived &&
              !isFullDocMode && (
                <>
                  <SegmentAdd
                    importStatus={importStatus}
                    clearImportStatus={resetImportStatus}
                    showNewSegmentModal={showNewSegmentModal}
                    showBatchModal={showBatchModal}
                    embedding={embedding}
                  />
                  <Divider type="vertical" className="mx-3! h-[14px]! bg-divider-regular!" />
                </>
              )}
            {documentDetail && (
              <StatusItem
                status={documentDetail.display_status || 'available'}
                scene="detail"
                errorMessage={documentDetail.error || ''}
                textCls="font-semibold text-xs uppercase"
                detail={statusDetail}
                datasetId={datasetId}
                onUpdate={handleOperate}
                canEdit={canEditDocument}
              />
            )}
            <Operations
              scene="detail"
              embeddingAvailable={embeddingAvailable}
              detail={operationsDetail}
              datasetId={datasetId}
              onUpdate={handleOperate}
              className="w-[200px]!"
              canEdit={canEditDocument}
              canDownload={datasetACLCapabilities.canDocumentDownload}
              canDelete={datasetACLCapabilities.canDeleteFile}
              canViewSettings={canEditDocument}
            />
            <button
              type="button"
              aria-label={metadataToggleLabel}
              aria-pressed={showMetadata}
              title={metadataToggleLabel}
              className={style.layoutRightIcon}
              onClick={() => setShowMetadata(!showMetadata)}
            >
              {showMetadata ? (
                <span
                  aria-hidden="true"
                  className="i-ri-layout-left-2-line size-4 text-components-button-secondary-text"
                />
              ) : (
                <span
                  aria-hidden="true"
                  className="i-ri-layout-right-2-line size-4 text-components-button-secondary-text"
                />
              )}
            </button>
          </div>
        </div>
        <div className="flex flex-1 flex-row" style={{ height: 'calc(100% - 4rem)' }}>
          {isDetailLoading ? (
            <Loading type="app" />
          ) : (
            <div
              className={cn(
                'flex h-full min-w-0 grow flex-col',
                !embedding && isFullDocMode && 'relative px-11 pt-4',
                !embedding && !isFullDocMode && 'relative pt-3 pr-11 pl-5',
              )}
            >
              {embedding ? (
                <Embedding
                  detailUpdate={detailMutate}
                  indexingType={dataset?.indexing_technique}
                  retrievalMethod={dataset?.retrieval_model_dict?.search_method}
                />
              ) : (
                <Completed
                  embeddingAvailable={embeddingAvailable}
                  showNewSegmentModal={newSegmentModalVisible}
                  onNewSegmentModalChange={setNewSegmentModalVisible}
                  importStatus={importStatus}
                  archived={documentDetail?.archived}
                />
              )}
            </div>
          )}
          <FloatRightContainer
            showClose
            isOpen={showMetadata}
            onClose={() => setShowMetadata(false)}
            isMobile={isMobile}
            panelClassName="justify-start!"
          >
            <Metadata
              className="mt-3 mr-2"
              datasetId={datasetId}
              documentId={documentId}
              docDetail={docDetail}
              canEdit={canEditDocument}
            />
          </FloatRightContainer>
        </div>
        <BatchModal
          isShow={batchModalVisible}
          onCancel={hideBatchModal}
          onConfirm={runBatch}
          docForm={documentDetail?.doc_form as ChunkingMode}
        />
      </div>
    </DocumentContext.Provider>
  )
}

export default DocumentDetail
