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

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 { 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 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,
      is_preview: false,
    }, {
      onSuccess: () => {
        invalidDocumentList()
        push(`/datasets/${datasetId}/documents/${documentId}`)
      },
    })
  }, [datasetId, documentId, 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>) => {
    isPreview.current ? handlePreviewChunks(data) : handleProcess(data)
  }, [handlePreviewChunks, handleProcess])

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

  if (isError)
    return <AppUnavailable code={500} unknownReason={t('datasetCreation.error.unavailable') 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='flex h-full flex-1 flex-col px-14'>
        <LeftHeader title={t('datasetPipeline.documentSettings.title')} />
        <div className='grow overflow-y-auto'>
          <ProcessDocuments
            ref={formRef}
            lastRunInputData={lastRunData!.input_data}
            datasourceNodeId={lastRunData!.datasource_node_id}
            onProcess={onClickProcess}
            onPreview={onClickPreview}
            onSubmit={handleSubmit}
          />
        </div>
      </div>
      {/* Preview */}
      <div className='flex h-full flex-1 pl-2 pt-2'>
        <ChunkPreview
          dataSourceType={lastRunData!.datasource_type}
          files={files}
          onlineDocuments={onlineDocuments}
          websitePages={websitePages}
          isIdle={isIdle}
          isPending={isPending && isPreview.current}
          estimateData={estimateData}
          onPreview={onClickPreview}
          handlePreviewFileChange={noop}
          handlePreviewOnlineDocumentChange={noop}
          handlePreviewWebsitePageChange={noop}
        />
      </div>
    </div>
  )
}

export default PipelineSettings
