import Tooltip from '@mui/material/Tooltip/index.js'
import Typography from '@mui/material/Typography/index.js'
import classNames from 'classnames'
import { useEffect, useState } from 'react'

import { FERTILIZER_BONUS } from '../../constants.js'
import { cropItemIdToSeedItemMap, itemsMap } from '../../data/maps.js'
import { cropLifeStage, fertilizerType, itemType } from '../../enums.js'
import { pixel, plotStates } from '../../img/index.js'
import { SHOVELED } from '../../strings.js'
import { squareImgSx } from '../../styles/sx.js'
import { SHOVELED_PLOT } from '../../templates.js'
import { getCropLifecycleDuration } from '../../utils/getCropLifecycleDuration.js'
import { getCropLifeStage } from '../../utils/getCropLifeStage.js'
import { getPlotContentType } from '../../utils/getPlotContentType.js'
import { getPlotImage } from '../../utils/getPlotImage.js'
import { Div, Img } from '../Elements/index.js'
import FarmhandContext from '../Farmhand/Farmhand.context.js'

const colorGenericHighlight = 'rgba(255, 255, 255, 0.8)'

export const getBackgroundStyles = (
  plotContent: farmhand.plotContent | null
): string | undefined => {
  if (!plotContent) {
    return undefined
  }

  const backgroundImages: string[] = []

  if (plotContent.fertilizerType === fertilizerType.STANDARD) {
    backgroundImages.push(`url(${plotStates['fertilized-plot']})`)
  } else if (plotContent.fertilizerType === fertilizerType.RAINBOW) {
    backgroundImages.push(`url(${plotStates['rainbow-fertilized-plot']})`)
  }

  if ('wasWateredToday' in plotContent && plotContent.wasWateredToday) {
    backgroundImages.push(`url(${plotStates['watered-plot']})`)
  } else if ('isShoveled' in plotContent && plotContent.isShoveled) {
    backgroundImages.push(`url(${plotStates['shoveled-plot']})`)
  }

  return backgroundImages.length > 0 ? backgroundImages.join(', ') : undefined
}

/*!
 */
export const getDaysLeftToMature = (
  plotContent: farmhand.plotContent | farmhand.crop | null
): number | null =>
  // Need to check that daysWatered is > -1 here because it may be NaN (in the
  // case of non-crop items).
  plotContent &&
  (plotContent as any).daysWatered > -1 &&
  getPlotContentType(plotContent) === itemType.CROP
    ? Math.max(
        0,
        Math.ceil(
          (getCropLifecycleDuration(
            plotContent ? (itemsMap[plotContent.itemId] as any) : null
          ) -
            (plotContent as any).daysWatered) /
            (1 +
              (plotContent.fertilizerType === fertilizerType.NONE
                ? 0
                : FERTILIZER_BONUS))
        )
      )
    : null

export interface PlotProps {
  handlePlotClick?: (x: number, y: number) => void
  isInHoverRange?: boolean
  plotContent?: farmhand.plotContent | null
  selectedItemId: string
  setHoveredPlot?: (coords: { x: number | null; y: number | null }) => void
  x?: number
  y?: number
  image?: string
  lifeStage?: string | false | null
  canBeHarvested?: boolean
}

export const Plot = ({
  handlePlotClick,
  isInHoverRange,
  plotContent,
  selectedItemId,
  setHoveredPlot,
  x,
  y,

  image: propsImage,
  lifeStage: propsLifeStage,
  canBeHarvested: propsCanBeHarvested,
}: PlotProps) => {
  const image =
    propsImage ?? getPlotImage(plotContent ?? null, x ?? 0, y ?? 0) ?? ''

  const lifeStage =
    propsLifeStage !== undefined
      ? propsLifeStage
      : (plotContent &&
          getPlotContentType(plotContent) === itemType.CROP &&
          getCropLifeStage(plotContent)) ||
        null

  const canBeHarvested =
    propsCanBeHarvested !== undefined
      ? propsCanBeHarvested
      : lifeStage === cropLifeStage.GROWN ||
        (plotContent && getPlotContentType(plotContent) === itemType.WEED) ||
        false

  const item = plotContent ? itemsMap[plotContent.itemId] : null
  const daysLeftToMature = getDaysLeftToMature(plotContent ?? null)
  const isCrop =
    plotContent && getPlotContentType(plotContent) === itemType.CROP
  const isScarecow =
    (plotContent?.itemId ? itemsMap[plotContent.itemId] : null)?.type ===
    itemType.SCARECROW
  const [wasJustShoveled, setWasJustShoveled] = useState(false)
  const [initialIsShoveledState, setInitialIsShoveledState] = useState(
    Boolean(plotContent?.isShoveled)
  )

  useEffect(() => {
    if (
      !initialIsShoveledState &&
      plotContent?.isShoveled &&
      plotContent?.oreId
    ) {
      setWasJustShoveled(true)
    }
  }, [initialIsShoveledState, plotContent])

  useEffect(() => {
    if (plotContent === null) {
      setInitialIsShoveledState(false)
      setWasJustShoveled(false)
    }
  }, [plotContent])

  const showPlotImage = Boolean(
    image &&
      (wasJustShoveled ||
        plotContent?.itemId ||
        (plotContent && getPlotContentType(plotContent) === itemType.CROP))
  )

  let plotLabelText: string | null = null

  if (item) {
    const isPlotContentACropSeed =
      plotContent &&
      getPlotContentType(plotContent) === itemType.CROP &&
      getCropLifeStage(plotContent) === cropLifeStage.SEED

    const seedItem = cropItemIdToSeedItemMap[item.id]

    plotLabelText = isPlotContentACropSeed ? seedItem.name : item.name
  } else if (wasJustShoveled || plotContent?.isShoveled) {
    const oreId = plotContent?.oreId
    const oreItem = oreId ? itemsMap[oreId] : null

    plotLabelText = oreItem
      ? SHOVELED_PLOT('', oreItem as farmhand.item)
      : SHOVELED
  }

  const plot = (
    <Div
      {...{
        className: classNames('Plot', {
          'is-empty': !plotContent,
          'is-in-hover-range': isInHoverRange,

          // For crops
          crop: isCrop,
          'can-be-harvested': canBeHarvested,

          // For crops and scarecrows
          'can-be-fertilized':
            (isCrop && plotContent?.fertilizerType === fertilizerType.NONE) ||
            (isScarecow &&
              plotContent?.fertilizerType === fertilizerType.NONE &&
              selectedItemId === 'rainbow-fertilizer'),

          'can-be-mined': !plotContent,

          // For scarecrows and sprinklers
          'is-replantable': plotContent && item?.isReplantable,
        }),
        style: {
          backgroundImage: getBackgroundStyles(plotContent ?? null),
        },
        onClick: () => handlePlotClick?.(x ?? 0, y ?? 0),
        onMouseOver: () => setHoveredPlot?.({ x: x ?? null, y: y ?? null }),
      }}
      sx={{
        backgroundRepeat: 'no-repeat',
        backgroundSize: 'cover',
        border: 'solid 1px #000',
        flexGrow: 1,
        imageRendering: 'pixelated',
        '&:hover': {
          backgroundColor: colorGenericHighlight,
          cursor: 'pointer',
        },
        '&.is-in-hover-range': {
          borderColor: colorGenericHighlight,
        },
      }}
    >
      <Img
        {...{
          className: classNames('square', {
            ...(isCrop && {
              animated: canBeHarvested,
              heartBeat: canBeHarvested,
            }),
            ...(wasJustShoveled && {
              animated: true,
              'was-just-shoveled': true,
            }),
          }),
          style: {
            backgroundImage: showPlotImage ? `url(${image})` : undefined,
          },
          src: pixel,
          alt: plotLabelText ?? 'Empty plot',
        }}
        sx={{
          ...squareImgSx,
          '&.was-just-shoveled': {
            animationName: 'fadeAwayShoveledContent',
          },
          '@keyframes fadeAwayShoveledContent': {
            from: {
              opacity: 1,
              transform: 'translate3d(0, 0, 0) scale(1)',
            },
            to: {
              opacity: 0,
              visibility: 'hidden',
              transform: 'translate3d(0, -100%, 0) scale(0.75)',
            },
          },
        }}
      />
    </Div>
  )

  if (!plotContent) {
    return plot
  }

  return (
    <Tooltip
      followCursor
      {...{
        placement: 'top',
        title: (
          <>
            {plotLabelText ? <Typography>{plotLabelText}</Typography> : null}
            {isCrop && (
              <Typography>
                {daysLeftToMature
                  ? `Days of watering to mature: ${daysLeftToMature}`
                  : 'Ready to harvest!'}
              </Typography>
            )}
          </>
        ),
      }}
    >
      {plot}
    </Tooltip>
  )
}

export default function Consumer(props: Partial<PlotProps>) {
  return (
    <FarmhandContext.Consumer>
      {({ gameState, handlers }) => (
        <Plot {...{ ...gameState, ...handlers, ...props }} />
      )}
    </FarmhandContext.Consumer>
  )
}
