import React, { useEffect, useState } from 'react'
import KeyboardArrowUp from '@mui/icons-material/KeyboardArrowUp.js'
import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown.js'
import Button from '@mui/material/Button/index.js'
import Box from '@mui/material/Box/index.js'
import Card from '@mui/material/Card/index.js'
import CardHeader from '@mui/material/CardHeader/index.js'
import CardContent from '@mui/material/CardContent/index.js'
import CardActions from '@mui/material/CardActions/index.js'
import Tooltip from '@mui/material/Tooltip/index.js'
import Typography from '@mui/material/Typography/index.js'
import { array, bool, func, number, object } from 'prop-types'
import classNames from 'classnames'

import FarmhandContext, { ContextData } from '../Farmhand/Farmhand.context.js'
import { items } from '../../img/index.js'
import { itemsMap } from '../../data/maps.js'
import { itemIds as shopItemIds } from '../../data/shop-inventory.js'
import { noop } from '../../utils/noop.js'
import { moneyString } from '../../utils/moneyString.js'
import { inventorySpaceRemaining } from '../../utils/inventorySpaceRemaining.js'
import { isItemSoldInShop } from '../../utils/isItemSoldInShop.js'
import { getFinalCropItemFromSeedItem } from '../../utils/getFinalCropItemFromSeedItem.js'
import { getItemCurrentValue } from '../../utils/getItemCurrentValue.js'
import { getResaleValue } from '../../utils/getResaleValue.js'
import { getSalePriceMultiplier } from '../../utils/getSalePriceMultiplier.js'
import { integerString } from '../../utils/integerString.js'
import { getCropLifecycleDuration } from '../../utils/getCropLifecycleDuration.js'
import QuantityInput from '../QuantityInput/index.js'
import AnimatedNumber from '../AnimatedNumber/index.js'

interface ValueIndicatorProps {
  poorValue: boolean
}

const ValueIndicator = ({ poorValue }: ValueIndicatorProps) => (
  <Tooltip
    {...{
      arrow: true,
      placement: 'top',
      title: `${poorValue ? 'Poor' : 'Good'} opportunity`,
    }}
  >
    {poorValue ? (
      <KeyboardArrowDown color="error" />
    ) : (
      <KeyboardArrowUp color="primary" />
    )}
  </Tooltip>
)

type PurchaseValueIndicatorProps = Pick<farmhand.item, 'id' | 'value'> &
  Pick<farmhand.state, 'valueAdjustments'> & {
    poorValue?: boolean
  }

const PurchaseValueIndicator = ({
  id,
  value,
  valueAdjustments,

  poorValue = value > itemsMap[id].value,
}: PurchaseValueIndicatorProps) => (
  <ValueIndicator
    {...{
      id,
      poorValue,
      value,
      valueAdjustments,
    }}
  />
)

const SellValueIndicator = ({
  id,
  value,
  valueAdjustments,

  poorValue = value < itemsMap[id].value,
}: PurchaseValueIndicatorProps) => (
  <ValueIndicator
    {...{
      id,
      poorValue,
      value,
      valueAdjustments,
    }}
  />
)

export interface ItemProps {
  item?: farmhand.item
  completedAchievements?: ContextData['gameState']['completedAchievements']
  handleItemPurchaseClick?: ContextData['handlers']['handleItemPurchaseClick']
  handleItemSelectClick?: ContextData['handlers']['handleItemSelectClick']
  handleItemSellClick?: ContextData['handlers']['handleItemSellClick']
  historicalValueAdjustments: ContextData['gameState']['historicalValueAdjustments']
  inventory: ContextData['gameState']['inventory']
  inventoryLimit: ContextData['gameState']['inventoryLimit']
  isPurchaseView?: boolean
  isSelectView?: boolean
  isSelected?: boolean
  isSellView?: boolean
  money: ContextData['gameState']['money']
  playerInventoryQuantities: ContextData['gameState']['playerInventoryQuantities']
  showQuantity?: boolean
  valueAdjustments: ContextData['gameState']['valueAdjustments']
  adjustedValue?: number
  previousDayAdjustedValue?: number | null
  maxQuantityPlayerCanPurchase?: number
}

export const Item = ({
  item,
  completedAchievements,
  handleItemPurchaseClick,
  handleItemSelectClick,
  handleItemSellClick,
  historicalValueAdjustments,
  inventory,
  inventoryLimit,
  isPurchaseView,
  isSelectView,
  isSelected,
  isSellView,
  money,
  playerInventoryQuantities,
  showQuantity,
  valueAdjustments,

  item: {
    description,
    doesPriceFluctuate,
    id,
    isReplantable,
    name,
    type,
    value,
  } = {} as farmhand.item,

  // Note: These props are defaulted to 0 in the tests.
  adjustedValue = isSellView && isItemSoldInShop(item!)
    ? getResaleValue(item!)
    : getItemCurrentValue(item!, valueAdjustments),

  previousDayAdjustedValue = (isSellView && isItemSoldInShop(item!)) ||
  historicalValueAdjustments.length === 0 ||
  !doesPriceFluctuate
    ? null
    : getItemCurrentValue(item!, historicalValueAdjustments[0]),

  maxQuantityPlayerCanPurchase = Math.max(
    0,
    Math.min(
      Math.floor(money / adjustedValue),
      inventorySpaceRemaining({ inventory, inventoryLimit })
    )
  ),
}: ItemProps) => {
  const [purchaseQuantity, setPurchaseQuantity] = useState(1)
  const [sellQuantity, setSellQuantity] = useState(1)

  useEffect(() => {
    // TODO: Determine if this logic can be simplified to be more like the
    // useEffect function below.
    setPurchaseQuantity(
      Math.min(maxQuantityPlayerCanPurchase, Math.max(1, purchaseQuantity))
    )
  }, [maxQuantityPlayerCanPurchase, purchaseQuantity])

  useEffect(() => {
    setSellQuantity(Math.min(playerInventoryQuantities[id], sellQuantity))
  }, [id, playerInventoryQuantities, sellQuantity])

  const handleItemPurchase = () => {
    handleItemPurchaseClick?.(item!, purchaseQuantity)
    setPurchaseQuantity(Math.min(1, maxQuantityPlayerCanPurchase))
  }
  const handleItemSell = () => {
    handleItemSellClick?.(item!, sellQuantity)
    setSellQuantity(Math.min(1, playerInventoryQuantities[id]))
  }

  const avatar = (
    <img {...{ src: items[id as keyof typeof items] }} alt={name} />
  )

  let sellPrice = adjustedValue

  // #140 - never increase the value of items the shop sells otherwise they
  // can be bought and instantly resold for a profit to game the.. game
  if (!shopItemIds.has(id)) {
    sellPrice *= getSalePriceMultiplier(completedAchievements)
  }

  return (
    <Card
      {...{
        className: classNames('Item', {
          'is-selectable': isSelectView,
          'is-selected': isSelected,
        }),
        onClick: isSelectView ? () => handleItemSelectClick?.(item!) : noop,
        raised: isSelected,
      }}
      sx={{
        position: 'relative',
        cursor: isSelectView ? 'pointer' : undefined,
        '& img': { width: '3em' },
        '& svg': { marginBottom: '-0.25em' },
        '& .MuiCardContent-root': {
          paddingTop: 0,
          '& p': { paddingTop: '1em' },
        },
        '& .MuiCardHeader-subheader': { userSelect: 'none' },
      }}
    >
      <CardHeader
        {...{
          avatar:
            !isPurchaseView && description ? (
              <Tooltip
                {...{
                  arrow: true,
                  placement: 'top',
                  title: <Typography>{description}</Typography>,
                }}
              >
                {avatar}
              </Tooltip>
            ) : (
              avatar
            ),
          title: name,
          subheader: (
            <div>
              {isPurchaseView && (
                <p>
                  <Tooltip
                    {...{
                      arrow: true,
                      placement: 'top',
                      title:
                        previousDayAdjustedValue === null
                          ? ''
                          : `Yesterday's price: ${moneyString(
                              previousDayAdjustedValue
                            )}`,
                    }}
                  >
                    <span>
                      Price:{' '}
                      <AnimatedNumber
                        {...{ number: adjustedValue, formatter: moneyString }}
                      />
                    </span>
                  </Tooltip>
                  {completedAchievements?.['unlock-crop-price-guide'] &&
                    valueAdjustments[id] && (
                      <PurchaseValueIndicator
                        {...{ id, value: adjustedValue, valueAdjustments }}
                      />
                    )}
                </p>
              )}
              {isPurchaseView && (
                <p>
                  Total:{' '}
                  {purchaseQuantity ? (
                    <AnimatedNumber
                      {...{
                        number: purchaseQuantity * adjustedValue,
                        formatter: moneyString,
                      }}
                    />
                  ) : null}
                </p>
              )}
              {isSellView && (
                <p>
                  <Tooltip
                    {...{
                      arrow: true,
                      placement: 'top',
                      title:
                        previousDayAdjustedValue === null
                          ? ''
                          : `Yesterday's sell price: ${moneyString(
                              previousDayAdjustedValue
                            )}`,
                    }}
                  >
                    <span>
                      Sell price:{' '}
                      <AnimatedNumber
                        {...{ number: sellPrice, formatter: moneyString }}
                      />
                    </span>
                  </Tooltip>
                  {completedAchievements?.['unlock-crop-price-guide'] &&
                    valueAdjustments[id] && (
                      <SellValueIndicator
                        {...{ id, value: adjustedValue, valueAdjustments }}
                      />
                    )}
                </p>
              )}
              {isSellView && (
                <p>
                  Total:{' '}
                  {sellQuantity ? (
                    <AnimatedNumber
                      {...{
                        number: sellQuantity * sellPrice,
                        formatter: moneyString,
                      }}
                    />
                  ) : null}
                </p>
              )}
              {showQuantity && (
                <p>
                  <strong>In inventory:</strong>{' '}
                  <AnimatedNumber
                    {...{
                      number: playerInventoryQuantities[id],
                      formatter: integerString,
                    }}
                  />
                </p>
              )}
              {isPurchaseView && (item as farmhand.seedItem).growsInto && (
                <p>
                  Days to mature:{' '}
                  {getCropLifecycleDuration({
                    cropTimeline:
                      getFinalCropItemFromSeedItem(item!)?.cropTimeline ??
                      getFinalCropItemFromSeedItem(item!)?.treeTimeline ??
                      [],
                  })}
                </p>
              )}
            </div>
          ),
        }}
      />
      {isPurchaseView && (description || isReplantable) && (
        <CardContent>
          {description && <Typography>{description}</Typography>}
          {isReplantable && (
            <Typography {...{ color: 'textSecondary' }}>
              Once planted in the field, this item can be returned to your
              inventory with the hoe and then replanted elsewhere.
            </Typography>
          )}
        </CardContent>
      )}
      <CardActions>
        {isSelectView && (
          <Button
            {...{
              // The onClick handler for this is bound on the parent Card for
              // better select-ability.
              className: 'select',
              color: 'primary',
              variant: isSelected ? 'contained' : 'outlined',
            }}
          >
            Select
          </Button>
        )}
        {isPurchaseView && (
          <>
            <Button
              {...{
                className: 'purchase',
                color: 'primary',
                disabled:
                  !purchaseQuantity || adjustedValue * purchaseQuantity > money,
                onClick: handleItemPurchase,
                variant: 'contained',
              }}
            >
              Buy
            </Button>
            <QuantityInput
              {...{
                handleSubmit: handleItemPurchase,
                handleUpdateNumber: setPurchaseQuantity,
                maxQuantity: maxQuantityPlayerCanPurchase,
                setQuantity: setPurchaseQuantity,
                value: purchaseQuantity,
              }}
            />
          </>
        )}
        {isSellView && (
          <Box display="flex">
            <Button
              {...{
                className: 'sell',
                color: 'error',
                disabled: sellQuantity === 0 || !sellQuantity,
                onClick: handleItemSell,
                variant: 'contained',
              }}
            >
              Sell
            </Button>
            <QuantityInput
              {...{
                handleSubmit: handleItemSell,
                handleUpdateNumber: setSellQuantity,
                maxQuantity: playerInventoryQuantities[id],
                setQuantity: setSellQuantity,
                value: sellQuantity,
              }}
            />
          </Box>
        )}
      </CardActions>
    </Card>
  )
}

Item.propTypes = {
  adjustedValue: number,
  completedAchievements: object.isRequired,
  handleItemPurchaseClick: func,
  handleItemSelectClick: func,
  handleItemSellClick: func,
  historicalValueAdjustments: array.isRequired,
  inventory: array.isRequired,
  inventoryLimit: number.isRequired,
  isPurchaseView: bool,
  isSelectView: bool,
  isSelected: bool,
  isSellView: bool,
  item: object.isRequired,
  money: number.isRequired,
  playerInventoryQuantities: object.isRequired,
  showQuantity: bool,
  valueAdjustments: object.isRequired,
}

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