import React, { useEffect, useState } from 'react'
import classNames from 'classnames'
import Button from '@mui/material/Button/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 Typography from '@mui/material/Typography/index.js'
import { array, func, number, object } from 'prop-types'

import { totalIngredientsInRecipe } from '../../utils/totalIngredientsInRecipe.js'
import { canMakeRecipe } from '../../utils/canMakeRecipe.js'
import { doesInventorySpaceRemain } from '../../utils/doesInventorySpaceRemain.js'
import { dollarString } from '../../utils/dollarString.js'
import { maxYieldOfRecipe } from '../../utils/maxYieldOfRecipe.js'
import { integerString } from '../../utils/integerString.js'
import { itemsMap } from '../../data/maps.js'
import { craftedItems } from '../../img/index.js'
import QuantityInput from '../QuantityInput/index.js'
import IngredientsList from '../IngredientsList/index.js'
import FarmhandContext from '../Farmhand/Farmhand.context.js'
import { INFINITE_STORAGE_LIMIT } from '../../constants.js'

const Recipe = ({
  handleMakeRecipeClick,
  inventory,
  inventoryLimit,
  playerInventoryQuantities,
  recipe,
}: {
  handleMakeRecipeClick: (recipeArg: farmhand.recipe, quantity: number) => void
  inventory: { id: string; quantity: number }[]
  inventoryLimit: number
  playerInventoryQuantities: Record<string, number>
  recipe: farmhand.recipe
}) => {
  const { id, name, description = '' } = recipe
  const [quantity, setQuantity] = useState(1)

  useEffect(() => {
    setQuantity(
      Math.min(maxYieldOfRecipe(recipe, inventory), Math.max(1, quantity))
    )
  }, [inventory, recipe, quantity])

  // Fixes https://github.com/jeremyckahn/farmhand/issues/25
  const spaceFreedByIngredientsConsumed =
    quantity * totalIngredientsInRecipe(recipe)

  const canBeMade =
    quantity > 0 &&
    canMakeRecipe(recipe, inventory, quantity) &&
    doesInventorySpaceRemain({
      inventory,
      // Without the Infinity coercion, this would break recipes for unlimited
      // inventoryLimits.
      inventoryLimit:
        (inventoryLimit === INFINITE_STORAGE_LIMIT
          ? Infinity
          : inventoryLimit) + spaceFreedByIngredientsConsumed,
    })

  const handleMakeRecipe = () => {
    if (canBeMade) {
      handleMakeRecipeClick(recipe, quantity)
    }
  }

  const maxQuantity = maxYieldOfRecipe(recipe, inventory)

  return (
    <Card
      {...{
        className: classNames('Recipe', { 'can-be-made': canBeMade }),
      }}
      sx={{
        position: 'relative',
        cursor: canBeMade ? 'pointer' : undefined,
        '& img': { width: '3em' },
        '& ul.card-list li': {
          margin: 0,
          '& p': { margin: 0 },
        },
      }}
    >
      <CardHeader
        {...{
          avatar: (
            <img
              {...{
                src: craftedItems[id as keyof typeof craftedItems],
                alt: name,
              }}
            />
          ),
          title: name,
          subheader: (
            <>
              <p>Sell price: {dollarString(itemsMap[id].value)}</p>
              <p>
                In Inventory: {integerString(playerInventoryQuantities[id])}
              </p>
              <IngredientsList
                {...{
                  playerInventoryQuantities,
                  recipe: recipe as any,
                }}
              />
            </>
          ),
        }}
      />
      {description && (
        <CardContent>
          <Typography>{description}</Typography>
        </CardContent>
      )}
      <CardActions>
        <Button
          {...{
            className: 'make-recipe',
            color: 'primary',
            disabled: !canBeMade || !quantity,
            onClick: handleMakeRecipe,
            variant: 'contained',
          }}
        >
          Make
        </Button>
        <QuantityInput
          {...{
            handleSubmit: handleMakeRecipe,
            handleUpdateNumber: setQuantity,
            maxQuantity,
            setQuantity,
            value: quantity,
          }}
        />
      </CardActions>
    </Card>
  )
}

Recipe.propTypes = {
  handleMakeRecipeClick: func.isRequired,
  inventory: array.isRequired,
  inventoryLimit: number.isRequired,
  playerInventoryQuantities: object.isRequired,
  recipe: object.isRequired,
}

export { Recipe }

export default function Consumer(props: Partial<Parameters<typeof Recipe>[0]>) {
  return (
    <FarmhandContext.Consumer>
      {({ gameState, handlers }) => (
        <Recipe
          {...({
            ...gameState,
            ...handlers,
            ...props,
          } as Parameters<typeof Recipe>[0])}
        />
      )}
    </FarmhandContext.Consumer>
  )
}
