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

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

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

export type ImageVaultDAMProps = {
  sdk: UiLocation
  config: ImageVaultDAMConfig
  initialData: InsertResponse | 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: InsertResponse
  onDelete: () => void
  onEdit: () => void
}

function Media({ media, onDelete, onEdit }: MediaProps) {
  // MediaConversions is an array but will only contain one object
  const { Url, Height, FormatHeight, Width, FormatWidth, Name, AspectRatio } =
    media.MediaConversions[0]

  const assetUrl = Url
  const title = media.Name
  const width = FormatWidth || Width
  const height = FormatHeight || Height
  const alt =
    media.Metadata?.find((meta) => meta.Name.includes("AltText_"))?.Value ||
    Name

  return (
    <div key={Url} style={{ fontFamily: "Inter" }}>
      <AssetCardVertical
        assetType="image"
        assetUrl={assetUrl}
        title={title}
        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={Name}
                  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,
  initialData,
}: ImageVaultDAMProps) {
  const [media, setMedia] = useState<InsertResponse | null>(initialData)

  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(document.body.scrollHeight), 0)
    }
  }, [frame])

  const handleMedia = useCallback(
    (result?: InsertResponse) => {
      if (field) {
        flushSync(() => {
          setMedia(result || null)
          // Data inside the field is supposed to be an empty object if nothing is selected
          field.setData(result || {})
          document.body.style.overflow = "hidden"
        })
      }

      updateFrameHeight()
    },
    [field, updateFrameHeight]
  )

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

  const handleEdit = useCallback(() => {
    const fieldData = field?.getData() as InsertResponse
    if (isInsertResponse(fieldData)) {
      cbModal({
        // @ts-expect-error: Component is badly typed
        component: (compProps) => (
          <ImageEditModal
            fieldData={fieldData}
            setData={handleMedia}
            {...compProps}
          />
        ),
        modalProps: {
          size: "max",
        },
      })
    }
  }, [field, handleMedia])

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

  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>
      <div>
        <FieldLabel htmlFor="imagevaultpicker" version="v2">
          ImageVault Asset
        </FieldLabel>
      </div>

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