"""zg_storage.contracts.flow_contract module."""

from __future__ import annotations

import json
from pathlib import Path
from typing import Any, Optional

from web3 import Web3

from ..evm import EvmClient
from .types import Submission


class FlowContractClient:
    """FlowContractClient class.

    Purpose:
        Wrapper for the Flow contract to submit log entries and query metadata."""

    def __init__(self, evm: EvmClient, address: str, abi_path: Optional[str] = None) -> None:
        self.evm = evm
        self.address = Web3.to_checksum_address(address)
        abi = self._load_abi(abi_path)
        self.contract = self.evm.w3.eth.contract(address=self.address, abi=abi)

    @staticmethod
    def _load_abi(abi_path: Optional[str]) -> Any:
        """Load the Flow contract ABI from a path or default location."""
        if abi_path is None:
            here = Path(__file__).resolve()
            abi_path = here.parent.parent / "storage-contracts-abis" / "Flow.json"
        else:
            abi_path = Path(abi_path)
        data = json.loads(abi_path.read_text())
        return data.get("abi", data)

    def submit(
        self,
        submission: Submission,
        value_wei: Optional[int] = None,
        gas: Optional[int] = None,
        gas_price: Optional[int] = None,
        nonce: Optional[int] = None,
    ) -> str:
        """Submit a flow entry transaction and return the tx hash."""
        if nonce is None:
            nonce = self.evm.w3.eth.get_transaction_count(self.evm.address())
        sub = {
            "data": {
                "length": submission.data.length,
                "tags": submission.data.tags,
                "nodes": [
                    {"root": node.root, "height": node.height} for node in submission.data.nodes
                ],
            },
            "submitter": Web3.to_checksum_address(submission.submitter),
        }

        tx = self.contract.functions.submit(sub).build_transaction(
            {
                "from": self.evm.address(),
                "value": value_wei or 0,
                **({"gas": gas} if gas is not None else {}),
                **({"gasPrice": gas_price} if gas_price is not None else {}),
                **({"nonce": nonce} if nonce is not None else {}),
            }
        )
        return self.evm.sign_and_send(tx)

    def market_address(self) -> str:
        return self.contract.functions.market().call()
