import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { UnitType, usePlayer } from '../providers/PlayerProvider';
import styles from '../styles/Army.module.css';
import { calculateBalance, toReadable } from './Counter';

const PRECISION = BigInt(10000);
const PRICE_FACTOR = BigInt(11500);

const base_cost: Record<UnitType, bigint> = {
  0: BigInt(380000),
  1: BigInt(3420000),
  2: BigInt(30096000),
  3: BigInt(255816000),
}

const profits: Record<UnitType, bigint> = {
  0: BigInt(2533),
  1: BigInt(27863),
  2: BigInt(306493),
  3: BigInt(3371423),
}

function calculateUnitPrice(unit: UnitType, currentLevel: number, units: number) {
  let rollingPriceCalculation = base_cost[unit];
  let price = BigInt(0);

  // Each level costs 15% more than previous
  for (let i = 0; i < currentLevel + units; i++) {
    if (i >= currentLevel) {
      price += rollingPriceCalculation;
    }
    rollingPriceCalculation = rollingPriceCalculation * PRICE_FACTOR / PRECISION;
  }
  return price;
}

function calculateProfitPerSecond(unit: UnitType, level: number) {
  // Each next unit scales progressivelly better
  return BigInt(level) * profits[unit]
}

const unitTypeToCss: Record<UnitType, string> = {
  0: styles.moloch_denier,
  1: styles.apprentice,
  2: styles.anointed,
  3: styles.champion
}

const unitTypeToName: Record<UnitType, string> = {
  0: "Moloch denier",
  1: "Apprentice",
  2: "Anointed",
  3: "Champion"
}

const defaultAvailabilityMap: Record<UnitType, boolean> = {
  0: false,
  1: false,
  2: false,
  3: false
}

const unitDiscoveredAt: Record<UnitType, bigint> = {
  0: BigInt(0),
  1: BigInt(300_0000),
  2: BigInt(2800_0000),
  3: BigInt(24000_0000)
}
const unitAvailableToDiscoverAt: Record<UnitType, bigint> = {
  0: BigInt(0),
  1: BigInt(200_0000),
  2: BigInt(2000_0000),
  3: BigInt(25000_0000),
}

interface UnitProps {
  addUnit: (unitType: UnitType) => void;
  unitType: UnitType;
  canPurchase: boolean;
  isShrouded: boolean;
  n_units: number
}

const Unit = ({ addUnit, unitType, canPurchase, isShrouded, n_units }: UnitProps) => {
  const [unitPrice, unitProfit] = useMemo(() => {
    return [
      toReadable(calculateUnitPrice(unitType, n_units, 1)),
      toReadable(calculateProfitPerSecond(unitType, n_units))
    ]
  }, [n_units, unitType]);
  return <div onClick={() => addUnit(unitType)} className={`${styles.armyUnit} ${canPurchase ? "" : styles.isUnavailable}`}>
    <div className={`
      ${unitTypeToCss[unitType]} 
      ${styles.person} 
      ${styles.static} 
      ${isShrouded ? styles.isShrouded : ""}
    `} />
    <span className={`${styles.unitName} ${styles.uiElement}`}>{isShrouded ? "???????" : unitTypeToName[unitType]}</span>
    {isShrouded ? null : <span className={`${styles.unitPrice} ${styles.uiElement}`}>{unitPrice} <small>GELD</small></span>}
    {n_units > 0 ? <span className={`${styles.unitSupply} ${styles.uiElement}`}>{n_units}</span> : null}
    {n_units > 0 ? <span className={`${styles.unitProfit} ${styles.uiElement}`}>{unitProfit} <small>per sec</small></span> : null}
  </div>
}

const Army = () => {
  const { army, addUnit, isRegistered, player, balance } = usePlayer()
  const [canPurchase, setCanPurchase] = useState<Record<UnitType, boolean>>(defaultAvailabilityMap);
  const [isShrouded, setIsShrouded] = useState<Record<UnitType, boolean>>(defaultAvailabilityMap);
  const [canKnowAbout, setCanKnowAbout] = useState<Record<UnitType, boolean>>(defaultAvailabilityMap);
  const balanceCount = useRef(BigInt(balance ?? 0))

  const setAvailabilities = useCallback(() => {
    if (isRegistered) {
      const totalMinted = (player?.total_minted ?? BigInt(0)) + (balanceCount.current - (balance ?? BigInt(0)));
      const n_units: Record<UnitType, number> = {
        0: army?.moloch_denier.level ?? 0,
        1: army?.apprentice.level ?? 0,
        2: army?.anointed.level ?? 0,
        3: army?.champion.level ?? 0,
      }
      const inShroud = {
        0: totalMinted < unitDiscoveredAt[0],
        1: totalMinted < unitDiscoveredAt[1],
        2: totalMinted < unitDiscoveredAt[2],
        3: totalMinted < unitDiscoveredAt[3],
      }
      const isKnown = {
        0: totalMinted >= unitAvailableToDiscoverAt[0],
        1: totalMinted >= unitAvailableToDiscoverAt[1],
        2: totalMinted >= unitAvailableToDiscoverAt[2],
        3: totalMinted >= unitAvailableToDiscoverAt[3],
      }
      const canActuallyBuy = {
        0: balanceCount.current >= calculateUnitPrice(0, n_units[0], 1) && isKnown[0] && !inShroud[0],
        1: balanceCount.current >= calculateUnitPrice(1, n_units[1], 1) && isKnown[1] && !inShroud[1],
        2: balanceCount.current >= calculateUnitPrice(2, n_units[2], 1) && isKnown[2] && !inShroud[2],
        3: balanceCount.current >= calculateUnitPrice(3, n_units[3], 1) && isKnown[3] && !inShroud[3],
      };
      setCanPurchase(canActuallyBuy)
      setIsShrouded(inShroud)
      setCanKnowAbout(isKnown)
    } else {
      setCanPurchase(defaultAvailabilityMap)
      setIsShrouded(defaultAvailabilityMap)
      setCanKnowAbout(defaultAvailabilityMap)
    }
  }, [
    army,
    balance,
    isRegistered,
    player?.total_minted
  ])

  useEffect(() => {
    const tickInterval = setInterval(() => {
      balanceCount.current = calculateBalance(
        balance ?? BigInt(0),
        army?.profit_per_second ?? BigInt(0),
        player?.last_raided_at ?? BigInt(0)
      );
      setAvailabilities()
    }, 100);
    return () => clearInterval(tickInterval)
  }, [balance, army?.profit_per_second, player?.last_raided_at, setAvailabilities])

  return <>
    <div className={`${styles.tavern_keeper} ${styles.person} ${styles.static}`} />
    <div className={styles.armyUnits}>
      {canKnowAbout[0] && <Unit n_units={army?.moloch_denier.level ?? 0} addUnit={addUnit} unitType={0} canPurchase={canPurchase[0]} isShrouded={isShrouded[0]} />}
      {canKnowAbout[1] && <Unit n_units={army?.apprentice.level ?? 0} addUnit={addUnit} unitType={1} canPurchase={canPurchase[1]} isShrouded={isShrouded[1]} />}
      {canKnowAbout[2] && <Unit n_units={army?.anointed.level ?? 0} addUnit={addUnit} unitType={2} canPurchase={canPurchase[2]} isShrouded={isShrouded[2]} />}
      {canKnowAbout[3] && <Unit n_units={army?.champion.level ?? 0} addUnit={addUnit} unitType={3} canPurchase={canPurchase[3]} isShrouded={isShrouded[3]} />}
    </div>
  </>
}

export default Army
