// Copyright 2017-2025 @pezkuwi/react-hooks authors & contributors
// SPDX-License-Identifier: Apache-2.0

import { useCallback, useEffect, useState } from 'react';

import { Abi } from '@pezkuwi/api-contract';
import { statics } from '@pezkuwi/react-api/statics';
import { createNamedHook } from '@pezkuwi/react-hooks';
import { u8aToString } from '@pezkuwi/util';

import store from './store.js';

interface AbiState {
  abi: string | null;
  abiName: string | null;
  contractAbi: Abi | null;
  errorText: string | null;
  isAbiError: boolean;
  isAbiValid: boolean;
  isAbiSupplied: boolean;
}

interface UseAbi extends AbiState {
  onChangeAbi: (u8a: Uint8Array, name: string) => void;
  onRemoveAbi: () => void;
}

function fromInitial (initialValue: [string | null | undefined, Abi | null | undefined], isRequired: boolean): AbiState {
  return {
    abi: initialValue[0] || null,
    abiName: null,
    contractAbi: initialValue[1] || null,
    errorText: null,
    isAbiError: false,
    isAbiSupplied: !!initialValue[1],
    isAbiValid: !isRequired || !!initialValue[1]
  };
}

const EMPTY: AbiState = {
  abi: null,
  abiName: null,
  contractAbi: null,
  errorText: null,
  isAbiError: false,
  isAbiSupplied: false,
  isAbiValid: false
};

function useAbiImpl (initialValue: [string | null | undefined, Abi | null | undefined] = [null, null], codeHash: string | null = null, isRequired = false): UseAbi {
  const [state, setAbi] = useState<AbiState>(() => fromInitial(initialValue, isRequired));

  useEffect(
    () => setAbi((state) =>
      initialValue[0] && state.abi !== initialValue[0]
        ? fromInitial(initialValue, isRequired)
        : state
    ),
    [initialValue, isRequired]
  );

  const onChangeAbi = useCallback(
    (u8a: Uint8Array, name: string): void => {
      const json = u8aToString(u8a);

      try {
        setAbi({
          abi: json,
          abiName: name.replace('.contract', '').replace('.json', '').replace('_', ' '),
          contractAbi: new Abi(json, statics.api.registry.getChainProperties()),
          errorText: null,
          isAbiError: false,
          isAbiSupplied: true,
          isAbiValid: true
        });

        codeHash && store.saveCode(codeHash, { abi: json });
      } catch (error) {
        console.error(error);

        setAbi({ ...EMPTY, errorText: (error as Error).message });
      }
    },
    [codeHash]
  );

  const onRemoveAbi = useCallback(
    (): void => {
      setAbi(EMPTY);

      codeHash && store.saveCode(codeHash, { abi: null });
    },
    [codeHash]
  );

  return {
    ...state,
    onChangeAbi,
    onRemoveAbi
  };
}

export default createNamedHook('useAbi', useAbiImpl);
