'use client'

import type { Release } from '@dify/contracts/enterprise/types.gen'
import { cn } from '@langgenius/dify-ui/cn'
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from '@langgenius/dify-ui/dropdown-menu'
import { toast } from '@langgenius/dify-ui/toast'
import { mutationOptions, useMutation } from '@tanstack/react-query'
import { useAtom, useAtomValue, useSetAtom } from 'jotai'
import { ScopeProvider } from 'jotai-scope'
import { useTranslation } from 'react-i18next'
import { consoleQuery } from '@/service/client'
import { openDeployDrawerAtom } from '../../../deploy-drawer/state'
import { deploymentRouteAppInstanceIdAtom } from '../../../route-state'
import { DETAIL_TABLE_ACTION_TRIGGER_CLASS_NAME } from '../../../shared/components/detail-table-styles'
import { TitleTooltip } from '../../../shared/components/title-tooltip'
import { isUndeployedDeploymentRow } from '../../../shared/domain/runtime-status'
import { DeleteReleaseDialog } from './delete-release-dialog'
import { buildDeployMenuSections, releaseUsageCount } from './deploy-release-menu-utils'
import { EditReleaseDialog } from './edit-release-dialog'
import { exportReleaseDsl } from './release-dsl-export'
import {
  deleteReleaseDialogOpenAtom,
  deployReleaseMenuAppInstanceNameAtom,
  deployReleaseMenuEnvironmentDeploymentsAtom,
  deployReleaseMenuEnvironmentDeploymentsIsErrorAtom,
  deployReleaseMenuEnvironmentDeploymentsIsLoadingAtom,
  deployReleaseMenuOpenAtom,
  openDeleteReleaseDialogAtom,
  openEditReleaseDialogAtom,
  releaseActionItemAtom,
  releaseActionLocalAtoms,
} from './state'

type ExportReleaseDslInput = {
  release: Release
  releaseId: string
  appInstanceName?: string
}

function DeployReleaseMenuContent({ onDeleted }: { onDeleted?: () => void }) {
  const { t } = useTranslation('deployments')
  const appInstanceId = useAtomValue(deploymentRouteAppInstanceIdAtom)
  const openDeployDrawer = useSetAtom(openDeployDrawerAtom)
  const { releaseId, releaseRows } = useAtomValue(releaseActionItemAtom)
  const [open, setOpen] = useAtom(deployReleaseMenuOpenAtom)
  const setDeleteReleaseDialogOpen = useSetAtom(deleteReleaseDialogOpenAtom)
  const openEditReleaseDialog = useSetAtom(openEditReleaseDialogAtom)
  const openDeleteReleaseDialog = useSetAtom(openDeleteReleaseDialogAtom)
  const environmentDeployments = useAtomValue(deployReleaseMenuEnvironmentDeploymentsAtom)
  const environmentDeploymentsIsLoading = useAtomValue(
    deployReleaseMenuEnvironmentDeploymentsIsLoadingAtom,
  )
  const environmentDeploymentsIsError = useAtomValue(
    deployReleaseMenuEnvironmentDeploymentsIsErrorAtom,
  )
  const appInstanceName = useAtomValue(deployReleaseMenuAppInstanceNameAtom)
  const deleteRelease = useMutation(
    consoleQuery.enterprise.releaseService.deleteRelease.mutationOptions(),
  )
  const exportReleaseDslMutation = useMutation(
    mutationOptions({
      mutationKey: ['deployments', 'release-dsl-export'],
      mutationFn: (input: ExportReleaseDslInput) => exportReleaseDsl(input),
    }),
  )

  const deploymentEnvironmentRows = environmentDeployments?.environmentDeployments ?? []
  const environments = deploymentEnvironmentRows.map((row) => row.environment)
  const deploymentRows = deploymentEnvironmentRows.filter((row) => !isUndeployedDeploymentRow(row))
  const targetRelease = releaseRows.find((release) => release.id === releaseId)

  if (!targetRelease) return null

  const release = targetRelease
  const targetReleaseName = release.displayName
  const deleteUsageCount = releaseUsageCount(releaseId, deploymentRows)
  const isCheckingDeleteUsage = open && environmentDeploymentsIsLoading
  const hasDeleteUsageCheckFailed = open && environmentDeploymentsIsError
  const isReleaseInUse = deleteUsageCount > 0
  const isDeletingRelease = deleteRelease.isPending
  const isExportingDsl = exportReleaseDslMutation.isPending
  const deleteDisabledReason = isCheckingDeleteUsage
    ? t(($) => $['versions.disabledReason.checkingDeployments'])
    : hasDeleteUsageCheckFailed
      ? t(($) => $['versions.disabledReason.checkDeploymentsFailed'])
      : isReleaseInUse
        ? t(($) => $['versions.disabledReason.releaseInUse'], { count: deleteUsageCount })
        : undefined
  const deleteActionDisabled =
    isDeletingRelease || isCheckingDeleteUsage || hasDeleteUsageCheckFailed || isReleaseInUse

  function handleExportDsl() {
    if (isExportingDsl) return

    exportReleaseDslMutation.mutate(
      { release, releaseId, appInstanceName },
      {
        onSuccess: () => {
          setOpen(false)
        },
        onError: () => {
          toast.error(t(($) => $['versions.exportDslFailed']))
        },
      },
    )
  }

  function handleDeleteRelease() {
    if (deleteActionDisabled) return

    deleteRelease.mutate(
      {
        params: {
          releaseId,
        },
      },
      {
        onSuccess: () => {
          setDeleteReleaseDialogOpen(false)
          toast.success(t(($) => $['versions.deleteSuccess'], { name: targetReleaseName }))
          onDeleted?.()
        },
        onError: () => {
          toast.error(t(($) => $['versions.deleteFailed']))
        },
      },
    )
  }

  const groupedRows = buildDeployMenuSections({
    environments,
    environmentDeployments: deploymentEnvironmentRows,
    releaseRows,
    releaseId,
    targetRelease: release,
    t: (selector, options) => t(selector, options),
  })

  return (
    <>
      <DropdownMenu modal={false} open={open} onOpenChange={setOpen}>
        <DropdownMenuTrigger
          aria-label={t(($) => $['versions.moreActions'])}
          className={DETAIL_TABLE_ACTION_TRIGGER_CLASS_NAME}
        >
          <span aria-hidden className="i-ri-more-fill size-4" />
        </DropdownMenuTrigger>
        {open && (
          <DropdownMenuContent placement="bottom-end" sideOffset={4} popupClassName="w-60">
            <DropdownMenuItem className="gap-2 px-3" onClick={openEditReleaseDialog}>
              <span aria-hidden className="i-ri-edit-line size-4 shrink-0 text-text-tertiary" />
              <span className="system-sm-regular text-text-secondary">
                {t(($) => $['versions.editRelease'])}
              </span>
            </DropdownMenuItem>
            <DropdownMenuItem
              disabled={isExportingDsl}
              aria-disabled={isExportingDsl}
              className={cn('gap-2 px-3', isExportingDsl && 'cursor-not-allowed opacity-60')}
              onClick={handleExportDsl}
            >
              <span
                aria-hidden
                className="i-ri-download-2-line size-4 shrink-0 text-text-tertiary"
              />
              <span className="system-sm-regular text-text-secondary">
                {isExportingDsl
                  ? t(($) => $['versions.exportingDsl'])
                  : t(($) => $['versions.exportDsl'])}
              </span>
            </DropdownMenuItem>
            {groupedRows.length > 0 && (
              <div className="my-1 border-t border-divider-subtle" aria-hidden />
            )}
            {groupedRows.map((section, sectionIndex) => (
              <div key={section.group}>
                {sectionIndex > 0 && (
                  <div className="my-1 border-t border-divider-subtle" aria-hidden />
                )}
                <div className="px-3 pt-1.5 pb-1 system-2xs-medium-uppercase text-text-quaternary">
                  {t(($) => $[`versions.groupHeader.${section.group}`])}
                </div>
                {section.rows.map((row) => {
                  const isDisabled = row.state === 'current' || row.state === 'deploying'
                  return (
                    <TitleTooltip
                      key={row.environmentId}
                      content={isDisabled ? row.disabledReason : undefined}
                    >
                      <DropdownMenuItem
                        disabled={isDisabled}
                        aria-disabled={isDisabled}
                        className={cn('gap-2 px-3', isDisabled && 'cursor-not-allowed opacity-60')}
                        onClick={() => {
                          if (isDisabled || !appInstanceId) return
                          setOpen(false)
                          openDeployDrawer({
                            appInstanceId,
                            environmentId: row.environmentId,
                            releaseId,
                          })
                        }}
                      >
                        <span className="system-sm-regular text-text-secondary">{row.label}</span>
                      </DropdownMenuItem>
                    </TitleTooltip>
                  )
                })}
              </div>
            ))}
            <div className="my-1 border-t border-divider-subtle" aria-hidden />
            <TitleTooltip content={deleteDisabledReason}>
              <DropdownMenuItem
                variant="destructive"
                disabled={deleteActionDisabled}
                aria-disabled={deleteActionDisabled}
                className={cn(
                  'gap-2 px-3',
                  deleteActionDisabled && 'cursor-not-allowed opacity-60',
                )}
                onClick={() => {
                  if (deleteActionDisabled) return
                  openDeleteReleaseDialog()
                }}
              >
                <span aria-hidden className="i-ri-delete-bin-line size-4 shrink-0" />
                <span className="system-sm-regular">{t(($) => $['versions.deleteRelease'])}</span>
              </DropdownMenuItem>
            </TitleTooltip>
          </DropdownMenuContent>
        )}
      </DropdownMenu>

      <EditReleaseDialog />

      <DeleteReleaseDialog isDeleting={isDeletingRelease} onConfirm={handleDeleteRelease} />
    </>
  )
}

export function DeployReleaseMenu({
  releaseId,
  releaseRows,
  onDeleted,
}: {
  releaseId: string
  releaseRows: Release[]
  onDeleted?: () => void
}) {
  return (
    <ScopeProvider
      key={releaseId}
      atoms={[[releaseActionItemAtom, { releaseId, releaseRows }], ...releaseActionLocalAtoms]}
      name="DeploymentReleaseActions"
    >
      <DeployReleaseMenuContent onDeleted={onDeleted} />
    </ScopeProvider>
  )
}
