import type { NotionPage } from '@/models/common'
import type { CrawlResultItem, CustomFile, FileIndexingEstimateResponse } from '@/models/datasets'
import type { OnlineDriveFile, PublishedPipelineRunPreviewResponse } from '@/models/pipeline'
import { noop } from 'es-toolkit/function'
import { useCallback, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import AppUnavailable from '@/app/components/base/app-unavailable'
import Loading from '@/app/components/base/loading'
import { useDatasetDetailContextWithSelector } from '@/context/dataset-detail'
import { DatasourceType } from '@/models/pipeline'
import { useRouter } from '@/next/navigation'
import { useInvalidDocumentDetail, useInvalidDocumentList } from '@/service/knowledge/use-document'
import { usePipelineExecutionLog, useRunPublishedPipeline } from '@/service/use-pipeline'
import ChunkPreview from '../../../create-from-pipeline/preview/chunk-preview'
import LeftHeader from './left-header'
import ProcessDocuments from './process-documents'

type PipelineSettingsProps = {
  datasetId: string
  documentId: string
}

const PipelineSettings = ({ datasetId, documentId }: PipelineSettingsProps) => {
  const { t } = useTranslation()
  const { push } = useRouter()
  const [estimateData, setEstimateData] = useState<FileIndexingEstimateResponse | undefined>(
    undefined,
  )
  const pipelineId = useDatasetDetailContextWithSelector((state) => state.dataset?.pipeline_id)

  const isPreview = useRef(false)
  const formRef = useRef<any>(null)

  const {
    data: lastRunData,
    isFetching: isFetchingLastRunData,
    isError,
  } = usePipelineExecutionLog({
    dataset_id: datasetId,
    document_id: documentId,
  })

  const files = useMemo(() => {
    const files: CustomFile[] = []
    if (lastRunData?.datasource_type === DatasourceType.localFile) {
      const { related_id, name, extension } = lastRunData.datasource_info
      files.push({
        id: related_id,
        name,
        extension,
      } as CustomFile)
    }
    return files
  }, [lastRunData])

  const websitePages = useMemo(() => {
    const websitePages: CrawlResultItem[] = []
    if (lastRunData?.datasource_type === DatasourceType.websiteCrawl) {
      const { content, description, source_url, title } = lastRunData.datasource_info
      websitePages.push({
        markdown: content,
        description,
        source_url,
        title,
      })
    }
    return websitePages
  }, [lastRunData])

  const onlineDocuments = useMemo(() => {
    const onlineDocuments: NotionPage[] = []
    if (lastRunData?.datasource_type === DatasourceType.onlineDocument) {
      const { workspace_id, page } = lastRunData.datasource_info
      onlineDocuments.push({
        workspace_id,
        ...page,
      })
    }
    return onlineDocuments
  }, [lastRunData])

  const onlineDriveFiles = useMemo(() => {
    const onlineDriveFiles: OnlineDriveFile[] = []
    if (lastRunData?.datasource_type === DatasourceType.onlineDrive) {
      const { id, type, name, size } = lastRunData.datasource_info
      onlineDriveFiles.push({
        id,
        name,
        type,
        size,
      })
    }
    return onlineDriveFiles
  }, [lastRunData])

  const { mutateAsync: runPublishedPipeline, isIdle, isPending } = useRunPublishedPipeline()

  const handlePreviewChunks = useCallback(
    async (data: Record<string, any>) => {
      if (!lastRunData) return
      const datasourceInfoList: Record<string, any>[] = []
      const documentInfo = lastRunData.datasource_info
      datasourceInfoList.push(documentInfo)
      await runPublishedPipeline(
        {
          pipeline_id: pipelineId!,
          inputs: data,
          start_node_id: lastRunData.datasource_node_id,
          datasource_type: lastRunData.datasource_type,
          datasource_info_list: datasourceInfoList,
          is_preview: true,
        },
        {
          onSuccess: (res) => {
            setEstimateData((res as PublishedPipelineRunPreviewResponse).data.outputs)
          },
        },
      )
    },
    [lastRunData, pipelineId, runPublishedPipeline],
  )

  const invalidDocumentList = useInvalidDocumentList(datasetId)
  const invalidDocumentDetail = useInvalidDocumentDetail()
  const handleProcess = useCallback(
    async (data: Record<string, any>) => {
      if (!lastRunData) return
      const datasourceInfoList: Record<string, any>[] = []
      const documentInfo = lastRunData.datasource_info
      datasourceInfoList.push(documentInfo)
      await runPublishedPipeline(
        {
          pipeline_id: pipelineId!,
          inputs: data,
          start_node_id: lastRunData.datasource_node_id,
          datasource_type: lastRunData.datasource_type,
          datasource_info_list: datasourceInfoList,
          original_document_id: documentId,
          is_preview: false,
        },
        {
          onSuccess: () => {
            invalidDocumentList()
            invalidDocumentDetail()
            push(`/datasets/${datasetId}/documents`)
          },
        },
      )
    },
    [
      datasetId,
      documentId,
      invalidDocumentDetail,
      invalidDocumentList,
      lastRunData,
      pipelineId,
      push,
      runPublishedPipeline,
    ],
  )

  const onClickProcess = useCallback(() => {
    isPreview.current = false
    formRef.current?.submit()
  }, [])

  const onClickPreview = useCallback(() => {
    isPreview.current = true
    formRef.current?.submit()
  }, [])

  const handleSubmit = useCallback(
    (data: Record<string, any>) => {
      if (isPreview.current) handlePreviewChunks(data)
      else handleProcess(data)
    },
    [handlePreviewChunks, handleProcess],
  )

  if (isFetchingLastRunData) {
    return <Loading type="app" />
  }

  if (isError)
    return (
      <AppUnavailable
        code={500}
        unknownReason={t(($) => $['error.unavailable'], { ns: 'datasetCreation' }) as string}
      />
    )

  return (
    <div className="relative flex h-[calc(100vh-56px)] min-w-[1024px] overflow-x-auto rounded-t-2xl border-t border-effects-highlight bg-background-default-subtle">
      <div className="h-full min-w-0 flex-1">
        <div className="flex h-full flex-col px-14">
          <LeftHeader title={t(($) => $['documentSettings.title'], { ns: 'datasetPipeline' })} />
          <div className="grow overflow-y-auto">
            <ProcessDocuments
              ref={formRef}
              lastRunInputData={lastRunData!.input_data}
              datasourceNodeId={lastRunData!.datasource_node_id}
              onProcess={onClickProcess}
              onPreview={onClickPreview}
              onSubmit={handleSubmit}
              isRunning={isPending}
            />
          </div>
        </div>
      </div>
      {/* Preview */}
      <div className="h-full min-w-0 flex-1">
        <div className="flex h-full flex-col pt-2 pl-2">
          <ChunkPreview
            dataSourceType={lastRunData!.datasource_type}
            localFiles={files}
            onlineDocuments={onlineDocuments}
            websitePages={websitePages}
            onlineDriveFiles={onlineDriveFiles}
            isIdle={isIdle}
            isPending={isPending && isPreview.current}
            estimateData={estimateData}
            onPreview={onClickPreview}
            handlePreviewFileChange={noop}
            handlePreviewOnlineDocumentChange={noop}
            handlePreviewWebsitePageChange={noop}
            handlePreviewOnlineDriveFileChange={noop}
          />
        </div>
      </div>
    </div>
  )
}

export default PipelineSettings
