import { useCallback, useEffect, useState } from "react"
import { flushSync } from "react-dom"

import {
  AssetCardVertical,
  Button,
  FieldLabel,
  cbModal,
} from "@contentstack/venus-components"
import { isInsertResponse, openImageVault } from "~/utils/imagevault"
import ImageEditModal from "./ImageEditModal"

import type UiLocation from "@contentstack/app-sdk/dist/src/uiLocation"
import type { CbModalProps } from "@contentstack/venus-components/build/components/Modal/Modal"
import type { ImageVaultAsset } from "~/types/imagevault"
import type { Lang } from "~/types/lang"
import type {
  EntryDataPublishDetails,
  ImageVaultDAMConfig,
} from "~/utils/imagevault"
import FullSizeImage from "./FullSizeImage"

export type ImageVaultDAMProps = {
  sdk: UiLocation
  config: ImageVaultDAMConfig
  imageVaultAsset: ImageVaultAsset | null
}

type DAMButtonProps = { onClick: () => void }

function DAMButton({ onClick }: DAMButtonProps) {
  return (
    <div style={{ padding: 2 }}>
      <Button
        onClick={onClick}
        buttonType="link"
        version="v2"
        icon="v2-Assets"
        iconAlignment="left"
        size="small"
        id="imagevaultpicker"
      >
        Choose a file
      </Button>
    </div>
  )
}

type MediaProps = {
  media: ImageVaultAsset
  onDelete: () => void
  onEdit: () => void
}

function Media({ media, onDelete, onEdit }: MediaProps) {
  const { url, meta, dimensions } = media
  const { width, height, aspectRatio } = dimensions
  const assetUrl = media.url
  const assetTitle = `Id: ${media.imageVaultId} - ${media.fileName}`

  const alt = meta.alt || meta.caption || ""
  const title = meta.caption || meta.alt || ""

  return (
    <div key={url} style={{ fontFamily: "Inter" }}>
      <AssetCardVertical
        assetType="image"
        assetUrl={assetUrl}
        title={assetTitle}
        version="v2"
        width={width}
        height={height}
        onDeleteClick={onDelete}
        onEditClick={onEdit}
        onFullScreenClick={() => {
          const cbModalProps: CbModalProps = {
            // @ts-expect-error: Component is badly typed
            component: (props) => {
              return (
                <FullSizeImage
                  // eslint-disable-next-line react/prop-types
                  onClose={props.closeModal}
                  imageUrl={url}
                  alt={alt}
                  title={title}
                  aspectRatio={aspectRatio}
                />
              )
            },
            modalProps: {
              size: "max",
              style: {
                content: {
                  display: "grid",
                  width: "90dvw",
                  height: "90dvh",
                  maxHeight: "100%",
                  gridTemplateRows: "auto 1fr",
                },
                overlay: {},
              },
            },
          }
          cbModal(cbModalProps)
        }}
      />
    </div>
  )
}

export default function ImageVaultDAM({
  sdk,
  config,
  imageVaultAsset,
}: ImageVaultDAMProps) {
  const [media, setMedia] = useState(imageVaultAsset)

  const field = sdk.location.CustomField?.field
  const frame = sdk.location.CustomField?.frame
  const entry = sdk.location.CustomField?.entry
  const stack = sdk.location.CustomField?.stack

  const updateFrameHeight = useCallback(() => {
    if (frame?.updateHeight) {
      // We need to recalculate the height of the iframe when an image is added.
      // Cannot use flushSync inside useEffect.
      setTimeout(() => frame.updateHeight(), 0)
    }
  }, [frame])

  const handleMedia = useCallback(
    (asset?: ImageVaultAsset) => {
      if (field) {
        flushSync(() => {
          const data = asset || null
          setMedia(data)
          field.setData(data)
          document.body.style.overflow = "hidden"
        })
      }

      updateFrameHeight()
    },
    [field, updateFrameHeight]
  )

  const handleEdit = useCallback(() => {
    const fieldData = field?.getData()
    if (fieldData) {
      cbModal({
        // @ts-expect-error: Component is badly typed
        component: (compProps) => (
          <ImageEditModal
            fieldData={fieldData}
            setData={handleMedia}
            {...compProps}
          />
        ),
        modalProps: {
          size: "max",
          style: {
            content: { maxHeight: "90dvh", maxWidth: "90dvw", width: "auto" },
            overlay: {},
          },
        },
      })
    }
  }, [field, handleMedia])

  useEffect(() => {
    updateFrameHeight()
  }, [updateFrameHeight])

  if (!field || !frame || !entry || !stack) {
    return <p>Initializing custom field...</p>
  }

  const fieldData = field.getData()

  if (isInsertResponse(fieldData)) {
    field.setData(imageVaultAsset)
  }

  const entryData: EntryDataPublishDetails = {
    //TODO: Add support for branches
    branch: "main",
    contentTypeUid: entry.content_type.uid,
    locale: entry.locale as Lang,
    stackApiKey: stack._data.api_key,
    title:
      entry.getField("title").getData().toString() ||
      `Untitled (${entry.content_type.uid})`,
    uid: entry._data.uid,
  }

  return (
    <div>
      <FieldLabel htmlFor="imagevaultpicker" version="v2">
        ImageVault Asset
      </FieldLabel>

      {media ? (
        <Media media={media} onDelete={handleMedia} onEdit={handleEdit} />
      ) : (
        <DAMButton
          onClick={() => {
            openImageVault({ config, entryData, onSuccess: handleMedia })
          }}
        />
      )}
    </div>
  )
}
