package org.kethereum.ens

import org.kethereum.eip137.model.ENSName
import org.kethereum.eip137.toNameHashByteArray
import org.kethereum.ens.generated.ContentHashResolverRPCConnector
import org.kethereum.ens.generated.ContentHashResolverTransactionGenerator
import org.kethereum.ens.generated.ENSRPCConnector
import org.kethereum.ens.generated.ResolverRPCConnector
import org.kethereum.erc1577.model.ContentHash
import org.kethereum.model.Address
import org.kethereum.rpc.EthereumRPC
import org.komputing.kethereum.erc181.resolver.ENSReverseResolverRPCConnector
import org.komputing.kethereum.erc634.ERC634RPCConnector

class ENS(private val rpc: EthereumRPC,
          ensAddress: Address = ENS_DEFAULT_CONTRACT_ADDRESS) {

    private val ens by lazy { ENSRPCConnector(ensAddress, rpc) }

    private fun <T> getFromResolver(nameHash: ByteArray, action: (resolver: Address) -> T): T? {
        val resolver = ens.resolver(nameHash)
        return if (resolver != null && resolver != ENS_ADDRESS_NOT_FOUND) {
            return action.invoke(resolver)
        } else {
            null
        }
    }

    /**
     * get the resolver Address for this ENSName
     */
    fun getResolver(name: ENSName) = ens.resolver(name.toNameHashByteArray())

    /**
     * get an Ethereum Address associated with this ENSName
     */
    fun getAddress(name: ENSName) = name.toNameHashByteArray().let {
        getFromResolver(it) { resolver ->
            ResolverRPCConnector(resolver, rpc).addr(it)
        }
    }

    /**
     * get a text record as defined in ERC-634
     * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-634.md
     */
    fun getTextRecord(name: ENSName, key: String) = name.toNameHashByteArray().let {
        getFromResolver(it) { resolver ->
            ERC634RPCConnector(resolver, rpc).text(it, key)
        }
    }

    /**
     * get an e-mail address
     * from EIP-634 text record
     */
    fun getEmail(name: ENSName) = getTextRecord(name, "email")

    /**
     * get an URL
     * from EIP-634 text record
     */
    fun getURL(name: ENSName) = getTextRecord(name, "url")

    /**
     * get an avatar - a URL to an image used as an avatar or logo
     * from EIP-634 text record
     */
    fun getAvatar(name: ENSName) = getTextRecord(name, "avatar")

    /**
     * get a description
     * from EIP-634 text record
     */
    fun getDescription(name: ENSName) = getTextRecord(name, "description")


    /**
     * get a notice
     * from EIP-634 text record
     */
    fun getNotice(name: ENSName) = getTextRecord(name, "notice")

    /**
     * get a list of keywords - A list of keywords, ordered by most significant first; clients that interpresent this field may choose a threshold beyond which to ignore
     * from EIP-634 text record
     */
    fun getKeywords(name: ENSName) = getTextRecord(name, "keywords")?.split(",")

    /**
     * get an github username
     * from EIP-634 text record
     */
    fun getGithubUserName(name: ENSName) = getTextRecord(name, "vnd.github")

    /**
     * get an twitter username
     * from EIP-634 text record
     */
    fun getTwitterUserName(name: ENSName) = getTextRecord(name, "vnd.twitter")

    /**
     * get an peepeth username
     * from EIP-634 text record
     */
    fun getPeepethUserName(name: ENSName) = getTextRecord(name, "vnd.peepeth")


    private fun reverseResolve(name: ENSName) = name.toNameHashByteArray().let {
        getFromResolver(it) { resolver ->
            ENSReverseResolverRPCConnector(resolver, rpc).name(it)
        }
    }

    fun reverseResolve(address: Address) = reverseResolve(ENSName(address.cleanHex.toLowerCase() + ".addr.reverse"))

    /**
     * get a content hash as defined in ERC-1577
     * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1577.md
     */
    fun getContentHash(name: ENSName) = name.toNameHashByteArray().let { nameHash ->
        getFromResolver(nameHash) { resolver ->
            ContentHashResolverRPCConnector(resolver, rpc).contenthash(nameHash)?.let {
                ContentHash(it)
            }
        }
    }

    /**
     * get the transaction to set content hash as defined in ERC-1577
     * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1577.md
     */
    fun getTransactionForSetContentHash(name: ENSName, contentHash: ContentHash) = name.toNameHashByteArray().let { nameHash ->
        getFromResolver(nameHash) { resolver ->
            ContentHashResolverTransactionGenerator(resolver).setContenthash(nameHash, contentHash.byteArray)
        }
    }

}