'use client'

import type { ReactNode } from 'react'
import type { AgentFileNode } from '@/features/agent-v2/agent-composer/form-state'
import { cn } from '@langgenius/dify-ui/cn'
import {
  DialogCloseButton,
  DialogContent,
  DialogDescription,
  DialogTitle,
} from '@langgenius/dify-ui/dialog'
import { FileTreeFile } from '@langgenius/dify-ui/file-tree'
import { ScrollArea } from '@langgenius/dify-ui/scroll-area'
import { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import Loading from '@/app/components/base/loading'
import { AgentFileTree } from '../files/tree'

type AgentSkillFileNode = AgentFileNode

type AgentSkillDetailSection = {
  id: string
  title: string
  paragraphs?: string[]
  items?: string[]
}

export type AgentSkillDetailDownloadAction = 'header' | 'preview'

export type AgentSkillDetail = {
  description: string
  fileCount?: number
  fileListHeader?: ReactNode
  fileListLoading?: boolean
  fileListPanelClassName?: string
  fileListTreeClassName?: string
  fileListTreeListClassName?: string
  fileListTitle?: string
  files: AgentSkillFileNode[]
  folderOpenState?: (context: { file: AgentSkillFileNode; depth: number }) => boolean
  filePreview?: {
    binary?: boolean
    content?: string
    downloadActionLoadingTarget?: AgentSkillDetailDownloadAction | null
    downloadUrl?: string
    fileName?: string
    imageData?: Blob
    isDownloadError?: boolean
    isDownloadLoading?: boolean
    isError?: boolean
    isImage?: boolean
    isLoading?: boolean
  }
  onFolderOpenChange?: (context: { file: AgentSkillFileNode; depth: number; open: boolean }) => void
  onFolderDoubleClick?: (context: { file: AgentSkillFileNode; depth: number }) => void
  onDownloadFile?: (action: AgentSkillDetailDownloadAction) => void
  onSelectFile?: (file: AgentSkillFileNode) => void
  renderFolderSuffix?: (context: { file: AgentSkillFileNode; depth: number }) => ReactNode
  selectedFileId?: string
  sections: AgentSkillDetailSection[]
}

const keepSkillFoldersClosed = () => false

function AgentSkillFileList({
  fileListHeader,
  fileListLoading,
  fileListTreeClassName,
  fileListTreeListClassName,
  fileListTitle,
  files,
  folderOpenState,
  onFolderOpenChange,
  onFolderDoubleClick,
  onSelectFile,
  renderFolderSuffix,
  selectedFileId,
}: {
  fileListHeader?: ReactNode
  fileListLoading?: boolean
  fileListTreeClassName?: string
  fileListTreeListClassName?: string
  fileListTitle?: string
  files: AgentSkillFileNode[]
  folderOpenState?: AgentSkillDetail['folderOpenState']
  onFolderOpenChange?: AgentSkillDetail['onFolderOpenChange']
  onFolderDoubleClick?: AgentSkillDetail['onFolderDoubleClick']
  onSelectFile?: (file: AgentSkillFileNode) => void
  renderFolderSuffix?: AgentSkillDetail['renderFolderSuffix']
  selectedFileId?: string
}) {
  const { t } = useTranslation('agentV2')

  if (fileListLoading) {
    return (
      <div className={cn('flex h-full flex-col bg-background-section', fileListTreeClassName)}>
        {fileListHeader ?? (
          <h3
            id="agent-skill-detail-files-heading"
            className="px-4 pt-3.5 pb-3 system-xl-semibold text-text-primary"
          >
            {fileListTitle ?? t(($) => $['agentDetail.configure.skills.detail.files'])}
          </h3>
        )}
        <div className="flex min-h-0 flex-1 items-center justify-center">
          <Loading type="area" />
        </div>
      </div>
    )
  }

  return (
    <AgentFileTree
      files={files}
      selectedFileId={selectedFileId}
      labelledBy="agent-skill-detail-files-heading"
      className={cn('h-full bg-background-section p-1', fileListTreeClassName)}
      listClassName={fileListTreeListClassName}
      scrollAreaClassName="flex-1"
      folderOpenStrategy={keepSkillFoldersClosed}
      folderOpenState={folderOpenState}
      onFolderOpenChange={onFolderOpenChange}
      onFolderDoubleClick={onFolderDoubleClick}
      renderFile={
        onSelectFile
          ? ({ depth, file, selected, children }) => (
              <FileTreeFile level={depth} selected={selected} onClick={() => onSelectFile(file)}>
                {children}
              </FileTreeFile>
            )
          : undefined
      }
      renderFolderSuffix={renderFolderSuffix}
      header={
        fileListHeader ?? (
          <h3
            id="agent-skill-detail-files-heading"
            className="px-4 pt-3.5 pb-3 system-xl-semibold text-text-primary"
          >
            {fileListTitle ?? t(($) => $['agentDetail.configure.skills.detail.files'])}
          </h3>
        )
      }
    />
  )
}

function AgentSkillDetailSectionBlock({ section }: { section: AgentSkillDetailSection }) {
  return (
    <section className="clear-none">
      <h3 className="system-sm-semibold text-text-primary">{section.title}</h3>
      {section.paragraphs?.map((paragraph) => (
        <p key={paragraph} className="mt-1 system-xs-regular text-text-secondary">
          {paragraph}
        </p>
      ))}
      {!!section.items?.length && (
        <ul className="mt-1 flex list-disc flex-col gap-0.5 pl-5 system-xs-regular text-text-secondary">
          {section.items.map((item) => (
            <li key={item} className="pl-0.5">
              {item}
            </li>
          ))}
        </ul>
      )}
    </section>
  )
}

function AgentSkillImagePreview({ fileName, imageData }: { fileName?: string; imageData: Blob }) {
  const setImageRef = useCallback(
    (image: HTMLImageElement | null) => {
      if (!image) return

      const objectUrl = URL.createObjectURL(imageData)
      image.src = objectUrl

      return () => {
        URL.revokeObjectURL(objectUrl)
      }
    },
    [imageData],
  )

  return (
    <div className="flex min-h-40 flex-1 items-start justify-center overflow-auto px-2 pb-4">
      <img
        ref={setImageRef}
        alt={fileName ?? ''}
        className="max-h-140 max-w-full rounded-lg object-contain"
      />
    </div>
  )
}

function AgentFilePreviewContent({
  binary,
  content,
  downloadActionLoadingTarget,
  downloadUrl,
  fileName,
  imageData,
  isDownloadError,
  isDownloadLoading,
  isError,
  isImage,
  isLoading,
  onDownloadFile,
}: {
  binary?: boolean
  content?: string
  downloadActionLoadingTarget?: AgentSkillDetailDownloadAction | null
  downloadUrl?: string
  fileName?: string
  imageData?: Blob
  isDownloadError?: boolean
  isDownloadLoading?: boolean
  isError?: boolean
  isImage?: boolean
  isLoading?: boolean
  onDownloadFile?: (action: AgentSkillDetailDownloadAction) => void
}) {
  const { t } = useTranslation('agentV2')
  const { t: tCommon } = useTranslation('common')
  const isPreviewDownloadLoading = downloadActionLoadingTarget === 'preview'

  if (isLoading || isDownloadLoading) {
    return (
      <div className="flex min-h-40 flex-1 items-center justify-center">
        <Loading type="area" />
      </div>
    )
  }

  if (isError || isDownloadError) {
    return (
      <p className="px-4 system-sm-regular text-text-tertiary">
        {t(($) => $['agentDetail.configure.files.preview.failed'])}
      </p>
    )
  }

  if (isImage) {
    if (imageData) return <AgentSkillImagePreview fileName={fileName} imageData={imageData} />
    if (downloadUrl) {
      return (
        <div className="flex min-h-40 flex-1 items-start justify-center overflow-auto px-2 pb-4">
          <img
            src={downloadUrl}
            alt={fileName ?? ''}
            className="max-h-140 max-w-full rounded-lg object-contain"
          />
        </div>
      )
    }
  }

  if (binary) {
    return (
      <div className="flex min-w-0 flex-wrap items-center gap-2 px-4">
        <span className="system-sm-regular text-text-tertiary">
          {t(($) => $['agentDetail.configure.files.preview.unsupported'])}
        </span>
        <a
          href={downloadUrl || '#'}
          aria-disabled={isPreviewDownloadLoading}
          onClick={(event) => {
            if (isPreviewDownloadLoading) {
              event.preventDefault()
              return
            }
            if (!downloadUrl) {
              event.preventDefault()
              onDownloadFile?.('preview')
            }
          }}
          target="_blank"
          rel="noreferrer"
          className="inline-flex min-w-0 items-center gap-1 rounded-md px-2 py-1 system-sm-medium text-text-accent outline-hidden hover:bg-state-base-hover focus-visible:ring-2 focus-visible:ring-state-accent-solid"
        >
          <span
            aria-hidden
            className={cn(
              'size-4 shrink-0',
              isPreviewDownloadLoading
                ? 'i-ri-loader-2-line animate-spin motion-reduce:animate-none'
                : 'i-ri-download-2-line',
            )}
          />
          <span className="shrink-0">
            {isPreviewDownloadLoading
              ? tCommon(($) => $['operation.downloading'])
              : tCommon(($) => $['operation.download'])}
          </span>
        </a>
      </div>
    )
  }

  if (!content) {
    return (
      <p className="px-4 system-sm-regular text-text-tertiary">
        {t(($) => $['agentDetail.configure.files.preview.empty'])}
      </p>
    )
  }

  const lines = content.split('\n').map((line, index) => ({
    content: line,
    key: `${index}:${line}`,
    lineNumber: String(index + 1).padStart(2, '0'),
  }))

  return (
    <div className="min-h-0 flex-1 overflow-auto px-2 pb-4 font-mono text-[13px] leading-[22px]">
      {lines.map((line) => (
        <div key={line.key} className="flex min-w-0 items-start">
          <span
            aria-hidden="true"
            className="w-7 shrink-0 pr-2 text-right text-text-quaternary select-none"
          >
            {line.lineNumber}
          </span>
          <code className="block min-w-0 flex-1 [overflow-wrap:anywhere] break-words whitespace-pre-wrap text-text-primary">
            {line.content}
          </code>
        </div>
      ))}
    </div>
  )
}

export function AgentSkillDetailDialog({
  skillName,
  detail,
}: {
  skillName: string
  detail: AgentSkillDetail
}) {
  const { t } = useTranslation('agentV2')
  const { t: tCommon } = useTranslation('common')
  const previewTitle = detail.filePreview?.fileName
  const isHeaderDownloadLoading = detail.filePreview?.downloadActionLoadingTarget === 'header'

  return (
    <DialogContent
      backdropProps={{ forceRender: true }}
      backdropClassName="fixed"
      className="flex h-[min(720px,calc(100dvh-2rem))] max-h-none w-[min(960px,calc(100vw-2rem))] flex-row overflow-hidden rounded-2xl p-0"
    >
      <div
        className={cn(
          'flex w-56 min-w-0 shrink-0 border-r-[0.5px] border-divider-subtle bg-background-section',
          detail.fileListPanelClassName,
        )}
      >
        <DialogDescription className="sr-only">{detail.description}</DialogDescription>
        <DialogTitle className="sr-only">{previewTitle || skillName}</DialogTitle>
        <div className="min-h-0 w-full">
          <AgentSkillFileList
            fileListHeader={detail.fileListHeader}
            fileListLoading={detail.fileListLoading}
            fileListTreeClassName={detail.fileListTreeClassName}
            fileListTreeListClassName={detail.fileListTreeListClassName}
            fileListTitle={detail.fileListTitle}
            files={detail.files}
            folderOpenState={detail.folderOpenState}
            onFolderOpenChange={detail.onFolderOpenChange}
            onFolderDoubleClick={detail.onFolderDoubleClick}
            selectedFileId={detail.selectedFileId}
            onSelectFile={detail.onSelectFile}
            renderFolderSuffix={detail.renderFolderSuffix}
          />
        </div>
      </div>
      <div className="flex min-w-0 flex-1 flex-col">
        <div className="flex shrink-0 items-start gap-2 px-4 pt-3.5 pb-2">
          <div className="flex min-w-0 flex-1 items-center gap-2">
            {!!previewTitle && (
              <h2
                className="min-w-0 truncate system-xl-semibold text-text-primary"
                title={previewTitle}
              >
                {previewTitle}
              </h2>
            )}
          </div>
          <div className="flex shrink-0 items-center gap-1">
            {detail.onDownloadFile && previewTitle && (
              <button
                type="button"
                aria-label={`${isHeaderDownloadLoading ? tCommon(($) => $['operation.downloading']) : tCommon(($) => $['operation.download'])} ${previewTitle}`}
                onClick={() => detail.onDownloadFile?.('header')}
                disabled={isHeaderDownloadLoading}
                className="flex size-7 shrink-0 items-center justify-center rounded-md text-text-tertiary outline-hidden hover:bg-state-base-hover hover:text-text-secondary focus-visible:bg-state-base-hover focus-visible:text-text-secondary focus-visible:ring-2 focus-visible:ring-state-accent-solid"
              >
                <span
                  aria-hidden
                  className={cn(
                    'size-4',
                    isHeaderDownloadLoading
                      ? 'i-ri-loader-2-line animate-spin motion-reduce:animate-none'
                      : 'i-ri-download-line',
                  )}
                />
              </button>
            )}
            <DialogCloseButton className="static size-7 shrink-0 rounded-md" />
          </div>
        </div>
        <ScrollArea
          className="relative min-h-0 flex-1 overflow-hidden has-[>_:first-child:focus-visible]:outline-2 has-[>_:first-child:focus-visible]:outline-offset-0 has-[>_:first-child:focus-visible]:outline-state-accent-solid"
          label={t(($) => $['agentDetail.configure.skills.detail.contentRegion'])}
          slotClassNames={{
            viewport: 'overscroll-contain outline-none focus-visible:outline-none',
            content: 'flex min-h-full w-full max-w-full min-w-0 flex-col gap-2',
          }}
        >
          {detail.filePreview && (
            <AgentFilePreviewContent
              binary={detail.filePreview.binary}
              content={detail.filePreview.content}
              downloadActionLoadingTarget={detail.filePreview.downloadActionLoadingTarget}
              downloadUrl={detail.filePreview.downloadUrl}
              fileName={detail.filePreview.fileName}
              imageData={detail.filePreview.imageData}
              isDownloadError={detail.filePreview.isDownloadError}
              isDownloadLoading={detail.filePreview.isDownloadLoading}
              isError={detail.filePreview.isError}
              isImage={detail.filePreview.isImage}
              isLoading={detail.filePreview.isLoading}
              onDownloadFile={detail.onDownloadFile}
            />
          )}
          {detail.sections.map((section) => (
            <div key={section.id} className="px-4">
              <AgentSkillDetailSectionBlock section={section} />
            </div>
          ))}
        </ScrollArea>
      </div>
    </DialogContent>
  )
}
