import type { AccountSettingTab } from '@/app/components/header/account-setting/constants'
import type { DataSourceProvider, NotionPage } from '@/models/common'
import type {
  CrawlOptions,
  CustomFile,
  DataSourceInfo,
  DataSourceType,
  LegacyDataSourceInfo,
  LocalFileInfo,
  OnlineDocumentInfo,
  UploadFileIdInfo,
  WebsiteCrawlInfo,
} from '@/models/datasets'
import { useBoolean } from 'ahooks'
import * as React from 'react'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import AppUnavailable from '@/app/components/base/app-unavailable'
import Loading from '@/app/components/base/loading'
import StepTwo from '@/app/components/datasets/create/step-two'
import AccountSetting from '@/app/components/header/account-setting'
import { ACCOUNT_SETTING_TAB } from '@/app/components/header/account-setting/constants'
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { useDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
import DatasetDetailContext from '@/context/dataset-detail'
import { useRouter } from '@/next/navigation'
import { useDocumentDetail, useInvalidDocumentDetail, useInvalidDocumentList } from '@/service/knowledge/use-document'

type DocumentSettingsProps = {
  datasetId: string
  documentId: string
}

const DocumentSettings = ({ datasetId, documentId }: DocumentSettingsProps) => {
  const { t } = useTranslation()
  const router = useRouter()
  const [isShowSetAPIKey, { setTrue: showSetAPIKey, setFalse: hideSetAPIkey }] = useBoolean()
  const [accountSettingTab, setAccountSettingTab] = React.useState<AccountSettingTab>(ACCOUNT_SETTING_TAB.PROVIDER)
  const { indexingTechnique, dataset } = useContext(DatasetDetailContext)
  const { data: embeddingsDefaultModel } = useDefaultModel(ModelTypeEnum.textEmbedding)
  const handleOpenAccountSetting = React.useCallback(() => {
    setAccountSettingTab(ACCOUNT_SETTING_TAB.PROVIDER)
    showSetAPIKey()
  }, [showSetAPIKey])

  const invalidDocumentList = useInvalidDocumentList(datasetId)
  const invalidDocumentDetail = useInvalidDocumentDetail()
  const saveHandler = () => {
    invalidDocumentList()
    invalidDocumentDetail()
    router.push(`/datasets/${datasetId}/documents/${documentId}`)
  }

  const cancelHandler = () => router.back()

  const { data: documentDetail, error } = useDocumentDetail({
    datasetId,
    documentId,
    params: { metadata: 'without' },
  })

  const dataSourceInfo = documentDetail?.data_source_info

  // Type guards for DataSourceInfo union
  const isLegacyDataSourceInfo = (info: DataSourceInfo | undefined): info is LegacyDataSourceInfo => {
    return !!info && 'upload_file' in info
  }
  const isWebsiteCrawlInfo = (info: DataSourceInfo | undefined): info is WebsiteCrawlInfo => {
    return !!info && 'source_url' in info && 'title' in info
  }
  const isOnlineDocumentInfo = (info: DataSourceInfo | undefined): info is OnlineDocumentInfo => {
    return !!info && 'page' in info
  }
  const isLocalFileInfo = (info: DataSourceInfo | undefined): info is LocalFileInfo => {
    return !!info && 'related_id' in info && 'transfer_method' in info
  }
  const isUploadFileIdInfo = (info: DataSourceInfo | undefined): info is UploadFileIdInfo => {
    return !!info && 'upload_file_id' in info
  }

  const legacyInfo = isLegacyDataSourceInfo(dataSourceInfo) ? dataSourceInfo : undefined
  const websiteInfo = isWebsiteCrawlInfo(dataSourceInfo) ? dataSourceInfo : undefined
  const onlineDocumentInfo = isOnlineDocumentInfo(dataSourceInfo) ? dataSourceInfo : undefined
  const localFileInfo = isLocalFileInfo(dataSourceInfo) ? dataSourceInfo : undefined
  const uploadFileIdInfo = isUploadFileIdInfo(dataSourceInfo) ? dataSourceInfo : undefined

  const currentPage = useMemo(() => {
    if (legacyInfo) {
      return {
        workspace_id: legacyInfo.notion_workspace_id ?? '',
        page_id: legacyInfo.notion_page_id ?? '',
        page_name: documentDetail?.name,
        page_icon: legacyInfo.notion_page_icon,
        type: documentDetail?.data_source_type,
      }
    }
    if (onlineDocumentInfo) {
      return {
        workspace_id: onlineDocumentInfo.workspace_id,
        page_id: onlineDocumentInfo.page.page_id,
        page_name: onlineDocumentInfo.page.page_name,
        page_icon: onlineDocumentInfo.page.page_icon,
        type: onlineDocumentInfo.page.type,
      }
    }
    return undefined
  }, [documentDetail?.data_source_type, documentDetail?.name, legacyInfo, onlineDocumentInfo])

  const files = useMemo<CustomFile[]>(() => {
    // Handle upload_file_id format
    if (uploadFileIdInfo) {
      return [{
        id: uploadFileIdInfo.upload_file_id,
        name: documentDetail?.name || '',
      } as unknown as CustomFile]
    }

    // Handle legacy upload_file format
    if (legacyInfo?.upload_file) {
      return [legacyInfo.upload_file as unknown as CustomFile]
    }

    // Handle local file info format
    if (localFileInfo) {
      const { related_id, name, extension } = localFileInfo
      return [{
        id: related_id,
        name,
        extension,
      } as unknown as CustomFile]
    }

    return []
  }, [uploadFileIdInfo, legacyInfo?.upload_file, localFileInfo, documentDetail?.name])

  const websitePages = useMemo(() => {
    if (!websiteInfo)
      return []
    return [{
      title: websiteInfo.title,
      source_url: websiteInfo.source_url,
      markdown: websiteInfo.content,
      description: websiteInfo.description,
    }]
  }, [websiteInfo])

  const crawlOptions = (dataSourceInfo && typeof dataSourceInfo === 'object' && 'includes' in dataSourceInfo && 'excludes' in dataSourceInfo)
    ? dataSourceInfo as unknown as CrawlOptions
    : undefined

  const websiteCrawlProvider = (websiteInfo?.provider ?? legacyInfo?.provider) as DataSourceProvider | undefined
  const websiteCrawlJobId = websiteInfo?.job_id ?? legacyInfo?.job_id

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

  return (
    <div className="flex" style={{ height: 'calc(100vh - 56px)' }}>
      <div className="grow">
        {!documentDetail && <Loading type="app" />}
        {dataset && documentDetail && (
          <StepTwo
            isAPIKeySet={!!embeddingsDefaultModel}
            onSetting={handleOpenAccountSetting}
            datasetId={datasetId}
            dataSourceType={documentDetail.data_source_type as DataSourceType}
            notionPages={currentPage ? [currentPage as unknown as NotionPage] : []}
            notionCredentialId={legacyInfo?.credential_id || onlineDocumentInfo?.credential_id || ''}
            websitePages={websitePages}
            websiteCrawlProvider={websiteCrawlProvider}
            websiteCrawlJobId={websiteCrawlJobId || ''}
            crawlOptions={crawlOptions}
            indexingType={indexingTechnique}
            isSetting
            documentDetail={documentDetail}
            files={files}
            onSave={saveHandler}
            onCancel={cancelHandler}
          />
        )}
      </div>
      {isShowSetAPIKey && (
        <AccountSetting
          activeTab={accountSettingTab}
          onTabChangeAction={setAccountSettingTab}
          onCancelAction={async () => {
            hideSetAPIkey()
          }}
        />
      )}
    </div>
  )
}

export default DocumentSettings
