"use client"

import { Dispatch, SetStateAction } from "react"
import { Tuple } from "./Tuple"
import { TupleArray } from "./TupleArray"
import { AbiParameter } from "abitype"
import {
  AddressInput,
  Bytes32Input,
  BytesInput,
  InputBase,
  IntegerInput,
  IntegerVariant,
} from "~~/components/xchange"
import { AbiParameterTuple } from "~~/utils/xchange/contract"

type ContractInputProps = {
  setForm: Dispatch<SetStateAction<Record<string, any>>>
  form: Record<string, any> | undefined
  stateObjectKey: string
  paramType: AbiParameter
}

/**
 * Generic Input component to handle input's based on their function param type
 */
export const ContractInput = ({
  setForm,
  form,
  stateObjectKey,
  paramType,
}: ContractInputProps) => {
  const inputProps = {
    name: stateObjectKey,
    value: form?.[stateObjectKey],
    placeholder: paramType.name
      ? `${paramType.type} ${paramType.name}`
      : paramType.type,
    onChange: (value: any) => {
      setForm(form => ({ ...form, [stateObjectKey]: value }))
    },
  }

  const renderInput = () => {
    switch (paramType.type) {
      case "address":
        return <AddressInput {...inputProps} />
      case "bytes32":
        return <Bytes32Input {...inputProps} />
      case "bytes":
        return <BytesInput {...inputProps} />
      case "string":
        return <InputBase {...inputProps} />
      case "tuple":
        return (
          <Tuple
            setParentForm={setForm}
            parentForm={form}
            abiTupleParameter={paramType as AbiParameterTuple}
            parentStateObjectKey={stateObjectKey}
          />
        )
      default:
        // Handling 'int' types and 'tuple[]' types
        if (paramType.type.includes("int") && !paramType.type.includes("[")) {
          return (
            <IntegerInput
              {...inputProps}
              variant={paramType.type as IntegerVariant}
            />
          )
        } else if (paramType.type.startsWith("tuple[")) {
          return (
            <TupleArray
              setParentForm={setForm}
              parentForm={form}
              abiTupleParameter={paramType as AbiParameterTuple}
              parentStateObjectKey={stateObjectKey}
            />
          )
        } else {
          return <InputBase {...inputProps} />
        }
    }
  }

  return (
    <div className="flex w-full flex-col gap-1.5">
      <div className="ml-2 flex items-center">
        {paramType.name && (
          <span className="mr-2 text-xs font-medium leading-none">
            {paramType.name}
          </span>
        )}
        <span className="block text-xs font-extralight leading-none">
          {paramType.type}
        </span>
      </div>
      {renderInput()}
    </div>
  )
}
