import { PermissionAction } from '@supabase/shared-types/out/constants'

import {
  getAnalyticsBucketPublicationName,
  getAnalyticsBucketS3KeyName,
  getAnalyticsBucketsDestinationName,
} from './AnalyticsBucketDetails.utils'
import { useAnalyticsBucketWrapperInstance } from './useAnalyticsBucketWrapperInstance'
import { useFDWDeleteMutation } from '@/data/fdw/fdw-delete-mutation'
import { useDeleteDestinationPipelineMutation } from '@/data/replication/delete-destination-pipeline-mutation'
import { useReplicationDestinationsQuery } from '@/data/replication/destinations-query'
import { useReplicationPipelinesQuery } from '@/data/replication/pipelines-query'
import { useDeletePublicationMutation } from '@/data/replication/publication-delete-mutation'
import { useReplicationPublicationsQuery } from '@/data/replication/publications-query'
import { useReplicationSourcesQuery } from '@/data/replication/sources-query'
import { useS3AccessKeyDeleteMutation } from '@/data/storage/s3-access-key-delete-mutation'
import { useStorageCredentialsQuery } from '@/data/storage/s3-access-key-query'
import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'

/**
 * Returns all the data that's associated to a specified analytics bucket (e.g publications, S3 keys, etc)
 * Used for cleaning up analytics bucket after deletion
 */
export const useAnalyticsBucketAssociatedEntities = (
  { projectRef, bucketId }: { projectRef?: string; bucketId?: string },
  options: { enabled: boolean } = { enabled: true }
) => {
  const { can: canReadS3Credentials } = useAsyncCheckPermissions(
    PermissionAction.STORAGE_ADMIN_READ,
    '*'
  )

  const {
    data: icebergWrapper,
    meta: icebergWrapperMeta,
    isLoading: isLoadingWrapperInstance,
  } = useAnalyticsBucketWrapperInstance({ bucketId }, { enabled: options.enabled })

  const { data: s3AccessKeys } = useStorageCredentialsQuery(
    { projectRef },
    { enabled: canReadS3Credentials && options.enabled }
  )
  const s3AccessKey = (s3AccessKeys?.data ?? []).find(
    (x) => x.description === getAnalyticsBucketS3KeyName(bucketId ?? '')
  )

  const { data: sourcesData } = useReplicationSourcesQuery(
    { projectRef },
    { enabled: options.enabled }
  )
  const sourceId = sourcesData?.sources.find((s) => s.name === projectRef)?.id

  const { data: publications = [] } = useReplicationPublicationsQuery(
    { projectRef, sourceId },
    { enabled: options.enabled }
  )
  const publication = publications.find(
    (p) => p.name === getAnalyticsBucketPublicationName(bucketId ?? '')
  )

  const { data: destinationsData } = useReplicationDestinationsQuery({ projectRef })
  const destinations = destinationsData?.destinations ?? []
  const destination = destinations.find(
    (x) => x.name === getAnalyticsBucketsDestinationName(bucketId ?? '')
  )

  const { data: pipelines } = useReplicationPipelinesQuery({ projectRef })
  const pipeline = pipelines?.pipelines.find((x) => x.config.publication_name === publication?.name)

  return {
    icebergWrapper,
    icebergWrapperMeta,
    s3AccessKey,
    sourceId,
    publication,
    pipeline,
    destination,
    isLoadingWrapperInstance,
  }
}

export const useAnalyticsBucketDeleteCleanUp = ({
  projectRef,
  bucketId,
}: {
  projectRef?: string
  bucketId?: string
}) => {
  const { data: project } = useSelectedProjectQuery()
  const {
    icebergWrapper,
    icebergWrapperMeta,
    s3AccessKey,
    publication,
    sourceId,
    pipeline,
    destination,
  } = useAnalyticsBucketAssociatedEntities({ projectRef, bucketId: bucketId })

  // Default error handlers from all mutations will be silenced
  const { mutateAsync: deleteFDW, isPending: isDeletingWrapper } = useFDWDeleteMutation({
    onError: () => {},
  })
  const { mutateAsync: deleteS3AccessKey, isPending: isDeletingKey } = useS3AccessKeyDeleteMutation(
    { onError: () => {} }
  )
  const { mutateAsync: deletePublication, isPending: isDeletingPublication } =
    useDeletePublicationMutation({ onError: () => {} })
  const { mutateAsync: deletePipeline, isPending: isDeletingPipeline } =
    useDeleteDestinationPipelineMutation({ onError: () => {} })

  const isDeleting =
    isDeletingWrapper || isDeletingKey || isDeletingPublication || isDeletingPipeline

  const mutateAsync = async () => {
    const connectionString = project?.connectionString

    if (!!icebergWrapper && !!icebergWrapperMeta) {
      try {
        await deleteFDW({
          projectRef,
          connectionString,
          wrapper: icebergWrapper,
          wrapperMeta: icebergWrapperMeta,
        })
      } catch (error: any) {
        console.error(`Failed to delete iceberg wrapper for ${bucketId}:`, error.message)
      }
    } else {
      console.warn(`Unable to find and delete iceberg wrapper for ${bucketId}`)
    }

    if (!!s3AccessKey) {
      try {
        await deleteS3AccessKey({ projectRef, id: s3AccessKey.id })
      } catch (error: any) {
        console.error(`Failed to delete S3 access key for: ${bucketId}`, error.message)
      }
    } else {
      console.warn(`Unable to find and delete corresponding S3 access key for ${bucketId}`)
    }

    if (!!pipeline && !!destination) {
      try {
        await deletePipeline({
          projectRef,
          destinationId: destination?.id,
          pipelineId: pipeline.id,
        })
      } catch (error: any) {
        console.error(`Failed to delete replication pipeline for: ${bucketId}`, error.message)
      }
    } else {
      console.warn(`Unable to find and delete replication pipeline for ${bucketId}`)
    }

    if (!!publication && !!sourceId) {
      try {
        await deletePublication({ projectRef, sourceId, publicationName: publication.name })
      } catch (error: any) {
        console.error(`Failed to delete replication publication for: ${bucketId}`, error.message)
      }
    } else {
      console.warn(`Unable to find and delete replication publication for ${bucketId}`)
    }
  }

  return { mutateAsync, isPending: isDeleting }
}
