import React, { createContext, ReactNode, useCallback, useContext, useEffect, useState } from 'react'
import { useAccount, useReadContract, useWriteContract } from 'wagmi'
import contractAbi from "../../../out/RaidGeld.sol/RaidGeld.json"
import { Hash, parseEther } from 'viem'
import contracts from '../../contract_address'
import WaitingForTxModal from '../components/WaitingForTxModal'

const { contractAddress, daoTokenAddress } = contracts
const abi = contractAbi.abi

export type UnitType = 0 | 1 | 2 | 3

export interface Player {
  created_at: bigint,
  last_raided_at: bigint,
  total_minted: bigint
}
export interface Army {
  anointed: { level: number }
  apprentice: { level: number }
  champion: { level: number }
  moloch_denier: { level: number }
  profit_per_second: bigint
}

export interface PlayerContextType {
  isRegistered: boolean,
  player: null | Player,
  army: null | Army,
  balance: bigint,
  register: (arg: "ETH" | "RGCVII") => void,
  raid: () => void,
  addUnit: (unit: UnitType) => void
}

const PlayerContext = createContext<PlayerContextType>({
  isRegistered: false,
  player: null,
  army: null,
  balance: BigInt(0),
  register: () => { },
  raid: () => { },
  addUnit: () => { }
});

const PlayerProvider = ({ children }: { children: ReactNode }) => {
  const { address, isConnected } = useAccount();
  const { writeContract, error } = useWriteContract();
  const [[txHash, callbackFn], setHashAndCallback] = useState<[Hash | null, () => void]>([null, () => { }])

  useEffect(() => {
    console.warn(error)
  }, [error])

  const resetHashAndCallback = useCallback(() => {
    setHashAndCallback([null, () => { }])
  }, [])

  const { data: isRegistered } = useReadContract({
    address: contractAddress,
    abi,
    functionName: 'isRegistered',
    args: [address],
    query: {
      enabled: isConnected,
      refetchInterval: 15,
    }
  });

  const { data: balance, } = useReadContract({
    address: contractAddress,
    abi,
    functionName: 'balanceOf',
    args: [address],
    query: {
      refetchInterval: 15,
      enabled: isConnected
    }
  });

  const { data: player } = useReadContract({
    address: contractAddress,
    abi,
    functionName: 'getPlayer',
    args: [address],
    query: {
      enabled: isConnected,
      refetchInterval: 15
    }
  });

  const { data: army } = useReadContract({
    address: contractAddress,
    abi,
    functionName: 'getArmy',
    args: [address],
    query: {
      enabled: isConnected,
      refetchInterval: 15
    }
  });

  console.log(balance, player, army)

  const register = useCallback((arg: "RGCVII" | "ETH") => {
    if (arg === 'ETH') {
      writeContract({
        abi,
        address: contractAddress,
        functionName: 'register_eth',
        value: parseEther("0.00005"),
      }, {
        onSuccess: (hash) => {
          setHashAndCallback([hash, resetHashAndCallback])
        }
      })
    } else if (arg === "RGCVII") {
      writeContract({
        abi,
        address: daoTokenAddress,
        functionName: 'approve',
        args: [contractAddress, parseEther("50")],
      }, {
        onSuccess: (hash) => {
          setHashAndCallback([
            hash,
            () => writeContract({
              abi,
              address: contractAddress,
              functionName: 'register_dao',
            }, {
              onSuccess: (hash) => {
                setHashAndCallback([hash, resetHashAndCallback])
              }
            })
          ])
        }
      });
    }
  }, [writeContract, resetHashAndCallback])

  const raid = useCallback(() => {
    writeContract({
      abi,
      address: contractAddress,
      functionName: 'raid',
    })
  }, [writeContract])

  const addUnit = useCallback((unit: UnitType) => {
    writeContract({
      abi,
      address: contractAddress,
      functionName: 'addUnit',
      args: [unit, 1]
    })
  }, [writeContract])

  return (
    <PlayerContext.Provider value={{
      isRegistered: isRegistered as boolean,
      player: player as Player,
      army: army as Army,
      balance: balance as bigint,
      register,
      raid,
      addUnit
    }}>
      {children}
      {txHash && <WaitingForTxModal hash={txHash} callbackFn={callbackFn} />}
    </PlayerContext.Provider>
  );
}

export const usePlayer = () => {
  return useContext(PlayerContext);
}

export default PlayerProvider

