import { normalize } from 'viem/ens'
import React, {
  useState,
  useEffect,
  useRef,
  isValidElementType,
  useCallback,
} from 'react'
import PropTypes from 'prop-types'
import _ from 'lodash'
import {
  getEthAddressType,
  isAddress,
  ETH_ADDRESS_TYPE,
} from './utils/address.js'
import Loader from './Loader.js'
import { SingleNameBlockies } from './Blockies.js'
import { PublicClient } from 'viem'

//import './style.css' Import in your own website

const ENS_NOT_FOUND = 'ENS name not found'

function Address(props) {
  const [resolvedAddress, setResolvedAddress] = useState(null)
  const inputValue = props.inputValue;
  const setInputValue = props.setterFunction;
  //const [inputValue, setInputValue] = useState('')
  const [isResolvingInProgressValue, setIsResolvingInProgress] = useState(0);
  const isResolvingInProgress = isResolvingInProgressValue > 0;
  const [error, setError] = useState(null)
  const [avatarURL, setAvatarURL] = useState(null)
  //const [ENS, setENS] = useState(null)
  const [provider, setProvider] = useState<PublicClient>(null);
  const currentInput = useRef()

  const inputDebouncerHandler = async (input) => {
    try {
      // Regular expression to check if input is a domain
      const domainRegex = new RegExp('^[^.]{1,63}(\\.[^.]{2,3})+$');
      const starProtocolDomainRegex = new RegExp('^[^.]{1,63}\\.(zk|linea|line|base|bas|ba|lin|li)$');
      const spaceIdDomainRegex = new RegExp('^[^.]{1,63}\\.(bnb|arb|bn|ar)$');

      if (starProtocolDomainRegex.test(input)) {
        if (input.endsWith('.zk')) {
          const urlToFetch = `https://omniapi.zkns.app/domain-resolver/getRecord/${input}`;
          // console.log("1urlToFetch", urlToFetch);
          const fetchData = await fetch(urlToFetch);
          const data = await fetchData.text();
          // console.log("starProtocolDomain data: ", data);
          if (isAddress(data)) {
            setError(null);
            setResolvedAddress(data);
            props.onResolve({
              address: data,
              name: input,
              type: ETH_ADDRESS_TYPE.address,
            });
            props.onError(null);
      
          } else {
            console.error("starProtocolDomain: Invalid domain");
          }  
        } else if (input.endsWith('.linea') | input.endsWith('.base')) {
          const urlToFetch = `https://mainnet-api.sns.so/domain/getRecord/${input}`;
          // console.log("2urlToFetch", urlToFetch);
          const result = await fetch(urlToFetch);
          // console.log("starProtocolDomain result: ", result);
          const json = await result.json();
          // console.log("starProtocolDomain json: ", json);
          const { data, code, message } = json;
          // console.log("starProtocolDomain", data, code, message);
          if (code === 200 && isAddress(data)) {
            setError(null);
            setResolvedAddress(data);
            props.onResolve({
              address: data,
              name: input,
              type: ETH_ADDRESS_TYPE.address,
            });
            props.onError(null);
          } else {
            console.error("starProtocolDomain: Invalid domain");
          }
        } else {
          // Todavía no ha llegado aquí.
          setError(null);
        }
      } else if (spaceIdDomainRegex.test(input)) {
        if (input.endsWith('.arb') || input.endsWith('.bnb')) {
          let tld;
          if (input.endsWith('.arb')) {
            tld = "arb1";
          } else {
            tld = "bnb";
          }

          const urlToFetch = `https://api.prd.space.id/v1/getAddress?tld=${tld}&domain=${input}`;
          // console.log("spaceId urlToFetch:", urlToFetch);
          const result = await fetch(urlToFetch);
          // console.log("spaceId result: ", result);
          const json = await result.json();
          // console.log("spaceId json: ", json);
          const { code, address } = json;
          // console.log("spaceId code, address: ", code, address);
          if (code === 0 && isAddress(address) && address !== "0x0000000000000000000000000000000000000000") {
            setError(null);
            setResolvedAddress(address);
            props.onResolve({
              address: address,
              name: input,
              type: ETH_ADDRESS_TYPE.address,
            });
            props.onError(null);
      
          } else {
            console.error("starProtocolDomain: Invalid domain");
          }  


        }
      } else if (domainRegex.test(input)) {
        const result = await resolveName(input)
        if (input === currentInput.current) {
          if (error !== null) setError(null);

          const { address, type, name, avatar } = result;
          if (type === ETH_ADDRESS_TYPE.name) {
            setResolvedAddress(address)
          } else if (type === ETH_ADDRESS_TYPE.address) {
            setResolvedAddress(name)
          }
          setAvatarURL(avatar)

          props.onResolve(result)
          props.onError(null)
        }
      } else {
        if (error) setError(null);
      }
      //if newest continue, otherwise ignore
    } catch (error) {
      setError(error.toString())
      setResolvedAddress(null)
      setAvatarURL(null)

      props.onResolve({
        address: input,
        name: null,
        type: null,
      })
      props.onError(error)
    }
  }

  const inputDebouncer = _.debounce(inputDebouncerHandler, 500)

  useEffect(() => {
    setProvider(props.provider);
    /* async function setup() {
       const options = {}
      if(props.ensAddress){
        options.ensAddress = props.ensAddress
      }
      if (props.provider) {
        options.customProvider = props.provider
      }
      const { ens } = await setupENS(options)
      setENS(ens) 
    } 
    setup() */
  }, [props.provider])

  const handleInput = useCallback(
    async (address) => {
      if (!address || address.length === 0) {
        setInputValue('')
        setError(null)
        setResolvedAddress(null)

        if (inputDebouncer) {
          inputDebouncer.cancel()
        }
      }

      setInputValue(address)
      if (inputDebouncer) {
        inputDebouncer(address)
      }
    },
    [inputDebouncer]
  )

  useEffect(() => {
    if (props.presetValue.length !== 0) {
      handleInput(props.presetValue)
    }
  }, [props.presetValue])


  useEffect(() => {
    if (props.inputValue.length === 0) {
      handleInput(props.inputValue)
    }
  }, [props.inputValue])


  if (!provider) {
    return <Loader className="loader" />
  }

  const handleResolver = async (fn) => {
    try {
      // console.log("ags BEFORE RESOLVER");
      setIsResolvingInProgress((current) => current+1);
      setResolvedAddress(null)
      return await fn()
    } catch (error) {
      if (error && error.message && error.message === ENS_NOT_FOUND) return
      throw error
    } finally {
      setIsResolvingInProgress((current) => current-1);
      // console.log("ags AFTER RESOLVER");
    }
  }

  const resolveName = async (inputValue) => {
    // update latest input resolving
    currentInput.current = inputValue
    const addressType = getEthAddressType(inputValue)
    const publicClient: PublicClient = provider;

    if (addressType === ETH_ADDRESS_TYPE.name) {
      return await handleResolver(async () => {
        const resolvedAddress = await publicClient.getEnsResolver({ name: normalize(inputValue)});
        const resolvedAvatar = await publicClient.getEnsAvatar({ name: normalize(inputValue)});

        return {
          input: inputValue,
          address: resolvedAddress,
          avatar: resolvedAvatar,
          name: inputValue,
          type: 'name',
      }})
    } else if (addressType === ETH_ADDRESS_TYPE.address) {
      return await handleResolver(async () => {
        
        // const tempName = await provider.lookupAddress(inputValue);
        const tempName = await publicClient.getEnsName({ address: inputValue});
        let tempAvatar;
        if (tempName) {
          // tempAvatar = await provider.getAvatar(tempName)
          tempAvatar = await publicClient.getEnsAvatar({ name: tempName});
        }

        return {
          input: inputValue,
          name: tempName,
          avatar: tempAvatar,
          address: inputValue,
          type: 'address',
      }})
    }

    setAvatarURL(null)

    throw 'Incorrect address or name'
  }

  const isResolveNameNotFound = () => {
    // console.log("ags resolvedAddress", resolvedAddress);
    // console.log("ags inputValue", inputValue);
    // console.log("ags isResolvingInProgress", isResolvingInProgress);
    return (
      !resolvedAddress &&
      inputValue &&
      !isResolvingInProgress &&
      getEthAddressType(inputValue) !== ETH_ADDRESS_TYPE.address
    )
  }

  const showBlockies = () => {
    if (props.showBlockies) {
      let address

      if (isAddress(inputValue)) {
        address = inputValue
      } else if (isAddress(resolvedAddress)) {
        address = resolvedAddress
      }

      if (address) {
        return (
          <SingleNameBlockies
            address={address.toLowerCase()}
            imageSize={30}
            className="blockies"
            avatarURL={avatarURL}
          />
        )
      }
    }
  }

  return (
    <div className={`cmp-address-wrapper ${props.className}`}>
      <div
        className={`w-full cmp-address  ${resolvedAddress ? 'resolved' : ''} ${
          error ? 'error' : ''
        }`}
      >
        <div className="input-wrapper">
          <div className="indicator">
            {isResolvingInProgress && <Loader className="loader" />}
            {!isResolvingInProgress && showBlockies()}
            {isResolveNameNotFound() && (
              <div
                alt="warning icon"
                className="icon-wrapper error-icon mt-2 ml-2"
              >{<svg width="19" height="17" xmlns="http://www.w3.org/2000/svg"><path d="M9.2456 5.0302c.5001-.1232 1.021.1232 1.2294.5954.0625.1643.1042.3285.1042.5133-.0209.5133-.0625 1.047-.1042 1.5604-.0417.8007-.1042 1.622-.1459 2.4227-.0208.2669-.0208.2874-.0208.5543-.0208.4312-.3542.7597-.7918.7597-.4376 0-.771-.308-.7918-.7391-.0625-1.2525-.1458-2.2996-.2083-3.552-.0209-.3285-.0417-.657-.0625-1.006-.0209-.5133.2917-.965.7917-1.1087m.271 9.4444c-.5835 0-1.0627-.4722-1.0627-1.047 0-.575.4792-1.0472 1.0626-1.0472.5834 0 1.0627.4723 1.0418 1.0677.0209.5543-.4792 1.0265-1.0418 1.0265M2.849 17h13.2936c2.1878 0 3.563-2.3611 2.4795-4.209L11.9544 1.4168c-1.0835-1.889-3.834-1.889-4.9174 0L.3694 12.791C-.6933 14.6594.661 17 2.8489 17" fill="#DC2E2E" fillRule="evenodd"/></svg>}
              </div>
            )}
            {props.DefaultIcon && !inputValue && <DefaultIcon />}
          </div>
          <input
            disabled={props.disabled}
            value={inputValue}
            onChange={(e) => handleInput(e.currentTarget.value)}
            placeholder={props.placeholder}
            spellCheck={false}
            name="ethereum"
          />
        </div>
        <div className="info-wrapper">
          {resolvedAddress && <div className="resolved">{resolvedAddress}</div>}
        </div>
      </div>
    </div>
  )
}

Address.propTypes = {
  provider: PropTypes.object.isRequired,
  placeholder: PropTypes.string,
  showBlockies: PropTypes.bool,
  DefaultIcon: (props, propName) => {
    if (props[propName] && !isValidElementType(props[propName])) {
      return new Error(
        `Invalid prop 'component' supplied to 'Route': the prop is not a valid React component`
      )
    }
  },
  onError: PropTypes.func,
  onResolve: PropTypes.func,
  className: PropTypes.string,
}

Address.defaultProps = {
  presetValue: '',
  placeholder: 'Enter Ethereum name or address',
  showBlockies: true,
  DefaultIcon: null,
  className: '',
  onError: function () {},
  onResolve: function () {},
}

export default Address
