import React, { useEffect, useState, forwardRef } from 'react'
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 Button from '@mui/material/Button/index.js'
import TextField from '@mui/material/TextField/index.js'
import AccountBalanceIcon from '@mui/icons-material/AccountBalance.js'
import NumberFormat from 'react-number-format'
import { func, number } from 'prop-types'

import FarmhandContext from '../Farmhand/Farmhand.context.js'
import { moneyString } from '../../utils/moneyString.js'
import { dollarString } from '../../utils/dollarString.js'
import { moneyTotal } from '../../utils/moneyTotal.js'
import {
  STANDARD_LOAN_AMOUNT,
  LOAN_INTEREST_RATE,
  LOAN_GARNISHMENT_RATE,
} from '../../constants.js'
import { Div } from '../Elements/index.js'

interface MoneyNumberFormatProps {
  max: number
  min: number
  onChange: (v: number) => void
  setLoanInputValue?: React.Dispatch<React.SetStateAction<number>>
  [key: string]: unknown
}

const MoneyNumberFormat = forwardRef(
  (
    { max, min, onChange, setLoanInputValue, ...rest }: MoneyNumberFormatProps,
    ref: React.ForwardedRef<HTMLInputElement>
  ) => (
    <NumberFormat
      fixedDecimalScale
      thousandSeparator
      getInputRef={ref}
      {...{
        ...rest,
        allowNegative: false,
        decimalScale: 2,
        prefix: '$',
        isAllowed: ({ floatValue = 0 }) => min >= 0 && floatValue <= max,
        onValueChange: ({ floatValue = 0 }) => onChange(floatValue),
      }}
    />
  )
)

interface AccountingViewProps {
  handleClickLoanPaydownButton: (amount: number) => void
  handleClickTakeOutLoanButton: (amount: number) => void
  loanBalance: number
  money: number
}

const AccountingView = ({
  handleClickLoanPaydownButton,
  handleClickTakeOutLoanButton,
  loanBalance,
  money,
}: AccountingViewProps) => {
  const [loanInputValue, setLoanInputValue] = useState(
    Math.min(loanBalance, money)
  )

  useEffect(() => setLoanInputValue(Math.min(loanBalance, money)), [
    loanBalance,
    money,
  ])

  return (
    <Div className="AccountingView">
      <Card sx={{ '& .MuiCardContent-root': { paddingTop: 0 } }}>
        <CardHeader
          {...{
            avatar: <AccountBalanceIcon />,
            title: 'Loan Balance',
            subheader: <p>{moneyString(loanBalance)}</p>,
          }}
        />
        <CardContent>
          <Div
            className="loan-container"
            sx={{
              '& p': { margin: '1em 0' },
              '& button': { margin: '1em' },
            }}
          >
            <TextField
              variant="standard"
              {...{
                value: loanInputValue,
                inputProps: {
                  max: loanBalance,
                  min: 0,

                  // Enable a helpful number input for iOS.
                  // https://css-tricks.com/finger-friendly-numerical-inputs-with-inputmode/
                  pattern: '[0-9]*',
                },

                onChange: value => {
                  // NOTE: value is naturally a number here, but it must be cast explicitly to work around an unhelpful type definition
                  setLoanInputValue(Number(value))
                },
                InputProps: {
                  inputComponent: MoneyNumberFormat,
                },
              }}
            />
            <Button
              {...{
                color: 'primary',
                disabled: loanBalance === 0,
                variant: 'contained',
                onClick: () => {
                  handleClickLoanPaydownButton(loanInputValue)
                  setLoanInputValue(loanBalance - loanInputValue)
                },
              }}
            >
              Pay into loan
            </Button>
            <p>
              You may take out a Hardship Assistance Loan if your funds fall
              below {dollarString(STANDARD_LOAN_AMOUNT)}. So long as you have an
              outstanding loan balance, all farm product sales are garnished by{' '}
              {LOAN_GARNISHMENT_RATE * 100}% until the loan is repaid. The loan
              interest rate is {LOAN_INTEREST_RATE * 100}% per day, compounded
              daily.
            </p>
          </Div>
          <Button
            {...{
              color: 'error',
              disabled: money >= STANDARD_LOAN_AMOUNT,
              onClick: () => {
                handleClickTakeOutLoanButton(STANDARD_LOAN_AMOUNT)
                setLoanInputValue(
                  Math.min(
                    moneyTotal(loanInputValue, STANDARD_LOAN_AMOUNT),
                    moneyTotal(money, STANDARD_LOAN_AMOUNT)
                  )
                )
              },
              variant: 'contained',
            }}
          >
            Take out a {dollarString(STANDARD_LOAN_AMOUNT)} loan
          </Button>
        </CardContent>
      </Card>
    </Div>
  )
}

AccountingView.propTypes = {
  handleClickTakeOutLoanButton: func.isRequired,
  handleClickLoanPaydownButton: func.isRequired,
  loanBalance: number.isRequired,
  money: number.isRequired,
}

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