import argparse
import csv
import getpass
import json
import logging
from uuid import UUID

from engineapi.models import Leaderboard

from . import actions
from . import db
from . import signatures
from . import data
from . import auth
from . import contracts_actions

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


def signing_server_list_handler(args: argparse.Namespace) -> None:
    try:
        instances = signatures.list_signing_instances(
            signing_instances=[] if args.instance is None else [args.instance]
        )
    except Exception as err:
        logger.error(f"Unhandled /list exception: {err}")
        return

    print(data.SignerListResponse(instances=instances).json())


def signing_server_wakeup_handler(args: argparse.Namespace) -> None:
    try:
        run_instances = signatures.wakeup_signing_instances(
            run_confirmed=args.confirmed, dry_run=args.dry_run
        )
    except signatures.AWSRunInstancesFail:
        return
    except Exception as err:
        logger.error(f"Unhandled /wakeup exception: {err}")
        return

    print(data.SignerWakeupResponse(instances=run_instances).json())


def signing_server_sleep_handler(args: argparse.Namespace) -> None:
    try:
        terminated_instances = signatures.sleep_signing_instances(
            signing_instances=[args.instance],
            termination_confirmed=args.confirmed,
            dry_run=args.dry_run,
        )
    except signatures.AWSDescribeInstancesFail:
        return
    except signatures.SigningInstancesNotFound:
        return
    except signatures.SigningInstancesTerminationLimitExceeded:
        return
    except signatures.AWSTerminateInstancesFail:
        return
    except Exception as err:
        logger.error(f"Unhandled /sleep exception: {err}")
        return

    print(data.SignerSleepResponse(instances=list(terminated_instances)).json())


def create_dropper_contract_handler(args: argparse.Namespace) -> None:
    try:
        with db.yield_db_session_ctx() as db_session:
            created_contract = actions.create_dropper_contract(
                db_session=db_session,
                blockchain=args.blockchain,
                dropper_contract_address=args.address,
                title=args.title,
                description=args.description,
                image_uri=args.image_uri,
            )
    except Exception as err:
        logger.error(f"Unhandled /create_dropper_contract exception: {err}")
        return
    print(created_contract)


def delete_dropper_contract_handler(args: argparse.Namespace) -> None:
    try:
        with db.yield_db_session_ctx() as db_session:
            removed_contract = actions.delete_dropper_contract(
                db_session=db_session,
                blockchain=args.blockchain,
                dropper_contract_address=args.address,
            )
    except Exception as err:
        logger.error(f"Unhandled /delete_dropper_contract exception: {err}")
        return
    print(removed_contract)


def list_dropper_contracts_handler(args: argparse.Namespace) -> None:
    try:
        with db.yield_db_session_ctx() as db_session:
            results = actions.list_dropper_contracts(
                db_session=db_session, blockchain=args.blockchain
            )
    except Exception as err:
        logger.error(f"Unhandled /list_dropper_contracts exception: {err}")
        return
    print(
        "\n".join(
            [
                data.DropperContractResponse(
                    id=result.id,
                    blockchain=result.blockchain,
                    address=result.address,
                    title=result.title,
                    description=result.description,
                    image_uri=result.image_uri,
                ).json()
                for result in results
            ]
        )
    )


def dropper_create_drop_handler(args: argparse.Namespace) -> None:
    try:
        with db.yield_db_session_ctx() as db_session:
            created_claim = actions.create_claim(
                db_session=db_session,
                dropper_contract_id=args.dropper_contract_id,
                claim_id=args.claim_id,
                title=args.title,
                description=args.description,
                terminus_address=args.terminus_address,
                terminus_pool_id=args.terminus_pool_id,
                claim_block_deadline=args.block_deadline,
            )
    except Exception as err:
        logger.error(f"Unhandled /create_dropper_claim exception: {err}")
        return
    print(created_claim)


def dropper_activate_drop_handler(args: argparse.Namespace) -> None:
    try:
        with db.yield_db_session_ctx() as db_session:
            activated_claim = actions.activate_claim(
                db_session=db_session,
                dropper_claim_id=args.dropper_claim_id,
            )
    except Exception as err:
        logger.error(f"Unhandled exception: {err}")
        return
    print(activated_claim)


def dropper_deactivate_drop_handler(args: argparse.Namespace) -> None:
    try:
        with db.yield_db_session_ctx() as db_session:
            deactivated_claim = actions.deactivate_claim(
                db_session=db_session,
                dropper_claim_id=args.dropper_claim_id,
            )
    except Exception as err:
        logger.error(f"Unhandled exception: {err}")
        return
    print(deactivated_claim)


def dropper_admin_pool_handler(args: argparse.Namespace) -> None:
    try:
        with db.yield_db_session_ctx() as db_session:
            (
                blockchain,
                terminus_address,
                terminus_pool_id,
            ) = actions.get_claim_admin_pool(
                db_session=db_session, dropper_claim_id=args.id
            )
    except Exception as err:
        logger.error(f"Unhandled exception: {err}")
        return

    print(
        f"Blockchain: {blockchain}, Terminus address: {terminus_address}, Pool ID: {terminus_pool_id}"
    )


def dropper_list_drops_handler(args: argparse.Namespace) -> None:
    try:
        with db.yield_db_session_ctx() as db_session:
            dropper_claims = actions.list_claims(
                db_session=db_session,
                dropper_contract_id=args.dropper_contract_id,
                active=args.active,
            )
    except Exception as err:
        logger.error(f"Unhandled /list_dropper_claims exception: {err}")
        return
    print(dropper_claims)


def dropper_delete_drop_handler(args: argparse.Namespace) -> None:
    try:
        with db.yield_db_session_ctx() as db_session:
            removed_claim = actions.delete_claim(
                db_session=db_session,
                dropper_claim_id=args.dropper_claim_id,
            )
    except Exception as err:
        logger.error(f"Unhandled /delete_dropper_claim exception: {err}")
        return
    print(removed_claim)


def add_claimants_handler(args: argparse.Namespace) -> None:
    """
    Load list of claimats from csv file and add them to the database.
    """

    claimants = []

    with open(args.claimants_file, "r") as f:
        reader = csv.DictReader(f)

        for row in reader:
            if len(row) != 2:
                logger.error(f"Invalid row: {row}")
                raise Exception("Invalid row")
            claimants.append({"address": row["address"], "amount": row["amount"]})

    # format as DropAddClaimantsRequest

    claimants = data.DropAddClaimantsRequest(
        dropper_claim_id=args.dropper_claim_id, claimants=claimants
    )

    with db.yield_db_session_ctx() as db_session:
        try:
            claimants = actions.add_claimants(
                db_session=db_session,
                dropper_claim_id=claimants.dropper_claim_id,
                claimants=claimants.claimants,
                added_by="cli",
            )
        except Exception as err:
            logger.error(f"Unhandled /add_claimants exception: {err}")
            return
    print(data.ClaimantsResponse(claimants=claimants).json())


def delete_claimants_handler(args: argparse.Namespace) -> None:
    """
    Read csv file and remove addresses in that list from claim
    """

    import csv

    addresses = []

    with open(args.claimants_file, "r") as f:
        reader = csv.DictReader(f)

        for row in reader:
            if len(row) != 1:
                logger.error(f"Invalid row: {row}")
                raise Exception("Invalid row")
            addresses.append(row["address"])

    # format as DropRemoveClaimantsRequest

    removing_addresses = data.DropRemoveClaimantsRequest(
        dropper_claim_id=args.dropper_claim_id, addresses=addresses
    )

    with db.yield_db_session_ctx() as db_session:
        try:
            addresses = actions.delete_claimants(
                db_session=db_session,
                dropper_claim_id=removing_addresses.dropper_claim_id,
                addresses=removing_addresses.addresses,
            )
        except Exception as err:
            logger.error(f"Unhandled /delete_claimants exception: {err}")
            return
    print(data.RemoveClaimantsResponse(addresses=addresses).json())


def list_claimants_handler(args: argparse.Namespace) -> None:
    """
    List claimants for a claim
    """

    with db.yield_db_session_ctx() as db_session:
        try:
            claimants = actions.get_claimants(
                db_session=db_session, dropper_claim_id=args.dropper_claim_id
            )
        except Exception as err:
            logger.error(f"Unhandled /list_claimants exception: {err}")
            return
    print(claimants)


def add_scores_handler(args: argparse.Namespace) -> None:
    """
    Adding scores to leaderboard
    """
    with open(args.input_file, "r") as f:
        json_input = json.load(f)

        try:
            new_scores = [data.Score(**score) for score in json_input]
        except Exception as err:
            logger.error(f"Can't parse json input in score format")
            logger.error(f"Invalid input: {err}")
            return

    with db.yield_db_session_ctx() as db_session:
        try:
            scores = actions.add_scores(
                db_session=db_session,
                leaderboard_id=args.leaderboard_id,
                scores=new_scores,
                overwrite=args.overwrite,
            )
        except Exception as err:
            logger.error(f"Unhandled /add_scores exception: {err}")
            return


def list_leaderboards_handler(args: argparse.Namespace) -> None:
    with db.yield_db_session_ctx() as db_session:
        Leaderboards = actions.list_leaderboards(
            db_session=db_session,
            limit=args.limit,
            offset=args.offset,
        )

        print(Leaderboards)


def create_leaderboard_handler(args: argparse.Namespace) -> None:
    with db.yield_db_session_ctx() as db_session:
        Leaderboard = actions.create_leaderboard(
            db_session=db_session,
            title=args.title,
            description=args.description,
        )

        print(Leaderboard)


def assign_resource_handler(args: argparse.Namespace) -> None:
    with db.yield_db_session_ctx() as db_session:
        try:
            resource_id = actions.assign_resource(
                db_session=db_session,
                resource_id=args.resource_id,
                leaderboard_id=args.leaderboard_id,
            )
            logger.info(
                f"leaderboard:{args.leaderboard_id} assign resource_id:{resource_id}"
            )
        except Exception as err:
            logger.error(f"Unhandled /assign_resource exception: {err}")
            return


def list_resources_handler(args: argparse.Namespace) -> None:
    with db.yield_db_session_ctx() as db_session:
        resources = actions.list_leaderboards_resources(db_session=db_session)

        logger.info(resources)


def revoke_resource_handler(args: argparse.Namespace) -> None:
    with db.yield_db_session_ctx() as db_session:
        try:
            resource = actions.revoke_resource(
                db_session=db_session,
                leaderboard_id=args.leaderboard_id,
            )
            logger.info(
                f"leaderboard:{args.leaderboard_id} revoke resource current resource_id:{resource}"
            )
        except Exception as err:
            logger.error(f"Unhandled /revoke_resource exception: {err}")
            return


def add_user_handler(args: argparse.Namespace) -> None:
    """
    Add permission to resource cross bugout api.
    """
    pass


def delete_user_handler(args: argparse.Namespace) -> None:
    """
    Delete read access from resource cross bugout api.
    """
    pass


def sign_handler(args: argparse.Namespace) -> None:
    # Prompt user to enter the password for their signing account
    password_raw = getpass.getpass(
        prompt=f"Enter password for signing account ({args.signer}): "
    )
    password = password_raw.strip()
    signer = signatures.create_account_signer(args.signer, password)
    signed_message = signer.sign_message(args.message)
    print(signed_message)


def main() -> None:
    parser = argparse.ArgumentParser(
        description="engineapi: The command line interface to Moonstream Engine API"
    )
    parser.set_defaults(func=lambda _: parser.print_help())
    subparsers = parser.add_subparsers()

    parser_sign = subparsers.add_parser("sign", description="Manually sign a message")
    parser_sign.add_argument(
        "-m", "--message", required=True, type=str, help="Message to sign (hex bytes)"
    )
    parser_sign.add_argument(
        "-s",
        "--signer",
        required=True,
        type=str,
        help="Path to keystore file for signer",
    )
    parser_sign.set_defaults(func=sign_handler)

    # Signing server parser
    parser_signing_server = subparsers.add_parser(
        "signing-server", description="Signing server commands"
    )
    parser_signing_server.set_defaults(
        func=lambda _: parser_signing_server.print_help()
    )
    subparsers_signing_server = parser_signing_server.add_subparsers(
        description="Signing server commands"
    )

    parser_signing_server_list = subparsers_signing_server.add_parser(
        "list", description="List signing servers"
    )
    parser_signing_server_list.add_argument(
        "-i",
        "--instance",
        type=str,
        help="Instance id to get",
    )
    parser_signing_server_list.set_defaults(func=signing_server_list_handler)

    parser_signing_server_wakeup = subparsers_signing_server.add_parser(
        "wakeup", description="Run signing server"
    )
    parser_signing_server_wakeup.add_argument(
        "-c",
        "--confirmed",
        action="store_true",
        help="Provide confirmation flag to run signing instance",
    )
    parser_signing_server_wakeup.add_argument(
        "-d",
        "--dry-run",
        action="store_true",
        help="Dry-run flag simulate instance start, using to check proper permissions",
    )
    parser_signing_server_wakeup.set_defaults(func=signing_server_wakeup_handler)

    parser_signing_server_sleep = subparsers_signing_server.add_parser(
        "sleep", description="Terminate signing server"
    )
    parser_signing_server_sleep.add_argument(
        "-i",
        "--instance",
        type=str,
        required=True,
        help="Instance id to terminate",
    )
    parser_signing_server_sleep.add_argument(
        "-c",
        "--confirmed",
        action="store_true",
        help="Provide confirmation flag to terminate signing instance",
    )
    parser_signing_server_sleep.add_argument(
        "-d",
        "--dry-run",
        action="store_true",
        help="Dry-run flag simulate instance termination, using to check proper permissions",
    )
    parser_signing_server_sleep.set_defaults(func=signing_server_sleep_handler)

    # Auth parser
    auth_parser = auth.generate_cli()
    subparsers.add_parser("auth", parents=[auth_parser], add_help=False)

    # engine-database parser
    parser_engine_database = subparsers.add_parser(
        "engine-db", description="engine-db commands"
    )
    parser_engine_database.set_defaults(
        func=lambda _: parser_engine_database.print_help()
    )
    subparsers_engine_database = parser_engine_database.add_subparsers(
        description="Engine-db commands"
    )

    parser_leaderboard = subparsers_engine_database.add_parser(
        "leaderboard", description="Leaderboard db commands"
    )
    parser_leaderboard.set_defaults(func=lambda _: parser_leaderboard.print_help())

    subparsers_leaderboard = parser_leaderboard.add_subparsers(
        description="Leaderboard db commands"
    )

    parser_leaderboard_create = subparsers_leaderboard.add_parser(
        "create-leaderboard", description="Create dropper contract"
    )
    parser_leaderboard_create.add_argument(
        "-t",
        "--title",
        type=str,
        required=False,
        help="Leaderboard title",
    )
    parser_leaderboard_create.add_argument(
        "-d",
        "--description",
        type=str,
        required=False,
        help="Leaderboard description",
    )

    parser_leaderboard_create.set_defaults(func=create_leaderboard_handler)

    parser_leaderboards_list = subparsers_leaderboard.add_parser(
        "list-leaderboards", description="List leaderboards"
    )
    parser_leaderboards_list.add_argument(
        "--limit",
        type=int,
        default=10,
    )
    parser_leaderboards_list.add_argument("--offset", type=int, default=0)
    parser_leaderboards_list.set_defaults(func=list_leaderboards_handler)

    parser_leaderboard_score = subparsers_leaderboard.add_parser(
        "add-scores", description="Add position to leaderboards score"
    )

    parser_leaderboard_score.add_argument(
        "--leaderboard-id",
        type=str,
        required=True,
        help="Contract description",
    )
    parser_leaderboard_score.add_argument(
        "--input-file",
        type=str,
        required=True,
        help="File with scores",
    )

    parser_leaderboard_score.add_argument("--overwrite", type=bool, default=True)

    parser_leaderboard_score.set_defaults(func=add_scores_handler)

    parser_leaderboard_permissions = subparsers_leaderboard.add_parser(
        "permissions", description="Manage leaderboard permissions"
    )

    parser_leaderboard_permissions.set_defaults(
        func=lambda _: parser_leaderboard_score.print_help()
    )

    subparsers_leaderboard_permissions = parser_leaderboard_permissions.add_subparsers(
        description="Manage leaderboard permissions"
    )

    parser_leaderboard_resource_assign = subparsers_leaderboard_permissions.add_parser(
        "assign", description="Assign resource to leaderboard"
    )

    parser_leaderboard_resource_assign.add_argument(
        "--leaderboard-id",
        type=str,
        required=True,
        help="Leaderboard id",
    )

    parser_leaderboard_resource_assign.add_argument(
        "--resource-id",
        type=UUID,
        required=False,
        help="Resource id",
    )

    parser_leaderboard_resource_assign.set_defaults(func=assign_resource_handler)

    parser_leaderboard_resource_revoke = subparsers_leaderboard_permissions.add_parser(
        "revoke", description="Revoke resource from leaderboard"
    )

    parser_leaderboard_resource_revoke.add_argument(
        "--leaderboard-id",
        type=str,
        required=True,
        help="Leaderboard id",
    )

    parser_leaderboard_resource_revoke.set_defaults(func=revoke_resource_handler)

    parser_leaderboard_resource_list = subparsers_leaderboard_permissions.add_parser(
        "list", description="List leaderboard resources and ids"
    )

    parser_leaderboard_resource_list.set_defaults(func=list_resources_handler)

    parser_leaderboard_resource_add_user = (
        subparsers_leaderboard_permissions.add_parser(
            "add-user", description="Add to user write access to leaderboard"
        )
    )
    parser_leaderboard_resource_add_user.add_argument(
        "--leaderboard-id",
        type=str,
        required=True,
        help="Leaderboard id",
    )

    parser_leaderboard_resource_add_user.add_argument(
        "--user-id",
        type=str,
        required=True,
        help="User id",
    )

    parser_leaderboard_resource_add_user.set_defaults(func=add_user_handler)

    parser_leaderboard_resource_remove_user = (
        subparsers_leaderboard_permissions.add_parser(
            "remove-user", description="Delete write access to leaderboard from user"
        )
    )

    parser_leaderboard_resource_remove_user.add_argument(
        "--leaderboard-id",
        type=str,
        required=True,
        help="Leaderboard id",
    )

    parser_leaderboard_resource_remove_user.add_argument(
        "--user-id",
        type=str,
        required=True,
        help="User id",
    )

    parser_leaderboard_resource_remove_user.set_defaults(func=delete_user_handler)

    parser_dropper = subparsers_engine_database.add_parser(
        "dropper", description="Dropper db commands"
    )
    parser_dropper.set_defaults(func=lambda _: parser_dropper.print_help())

    subparsers_dropper = parser_dropper.add_subparsers(
        description="Dropper db commands"
    )

    parser_dropper_contract_create = subparsers_dropper.add_parser(
        "create-contract", description="Create dropper contract"
    )
    parser_dropper_contract_create.add_argument(
        "-b",
        "--blockchain",
        type=str,
        required=True,
        help="Blockchain in wich contract was deployed",
    )
    parser_dropper_contract_create.add_argument(
        "-a",
        "--address",
        type=str,
        required=True,
        help="Contract address",
    )
    parser_dropper_contract_create.add_argument(
        "-t",
        "--title",
        type=str,
        required=False,
        help="Contract title",
    )
    parser_dropper_contract_create.add_argument(
        "-d",
        "--description",
        type=str,
        required=False,
        help="Contract description",
    )
    parser_dropper_contract_create.add_argument(
        "-i",
        "--image-uri",
        type=str,
        required=False,
        help="Contract image uri",
    )

    parser_dropper_contract_create.set_defaults(func=create_dropper_contract_handler)

    parser_dropper_contract_list = subparsers_dropper.add_parser(
        "list-contracts", description="List dropper contracts"
    )
    parser_dropper_contract_list.add_argument(
        "-b",
        "--blockchain",
        type=str,
        required=True,
        help="Blockchain in wich contract was deployed",
    )
    parser_dropper_contract_list.set_defaults(func=list_dropper_contracts_handler)

    parser_dropper_contract_delete = subparsers_dropper.add_parser(
        "delete-contract", description="Delete dropper contract"
    )
    parser_dropper_contract_delete.add_argument(
        "-b",
        "--blockchain",
        type=str,
        required=True,
        help="Blockchain in wich contract was deployed",
    )
    parser_dropper_contract_delete.add_argument(
        "-a",
        "--address",
        type=str,
        required=True,
        help="Contract address",
    )
    parser_dropper_contract_delete.set_defaults(func=delete_dropper_contract_handler)

    parser_dropper_create_drop = subparsers_dropper.add_parser(
        "create-drop", description="Create dropper drop"
    )
    parser_dropper_create_drop.add_argument(
        "-c",
        "--dropper-contract-id",
        type=str,
        required=True,
        help="Dropper contract id",
    )
    parser_dropper_create_drop.add_argument(
        "-t",
        "--title",
        type=str,
        required=True,
        help="Drop title",
    )
    parser_dropper_create_drop.add_argument(
        "-d",
        "--description",
        type=str,
        required=True,
        help="Drop description",
    )
    parser_dropper_create_drop.add_argument(
        "-b",
        "--block-deadline",
        type=int,
        required=True,
        help="Block deadline at which signature will be not returned",
    )
    parser_dropper_create_drop.add_argument(
        "-T",
        "--terminus-address",
        type=str,
        required=True,
        help="Terminus address",
    )
    parser_dropper_create_drop.add_argument(
        "-p",
        "--terminus-pool-id",
        type=int,
        required=True,
        help="Terminus pool id",
    )
    parser_dropper_create_drop.add_argument(
        "-m",
        "--claim-id",
        type=int,
        help="Claim id",
    )

    parser_dropper_create_drop.set_defaults(func=dropper_create_drop_handler)

    parser_dropper_activate_drop = subparsers_dropper.add_parser(
        "activate-drop", description="Activate dropper drop"
    )
    parser_dropper_activate_drop.add_argument(
        "-c",
        "--dropper-claim-id",
        type=str,
        required=True,
        help="Dropper claim id",
    )
    parser_dropper_activate_drop.set_defaults(func=dropper_activate_drop_handler)

    parser_dropper_deactivate_drop = subparsers_dropper.add_parser(
        "deactivate-drop", description="Deactivate dropper drop"
    )
    parser_dropper_deactivate_drop.add_argument(
        "-c",
        "--dropper-claim-id",
        type=str,
        required=True,
        help="Dropper claim id",
    )
    parser_dropper_deactivate_drop.set_defaults(func=dropper_deactivate_drop_handler)

    parser_dropper_get_claim_admin_pool = subparsers_dropper.add_parser(
        "admin-pool", description="Get admin pool for drop"
    )
    parser_dropper_get_claim_admin_pool.add_argument(
        "-i", "--id", required=True, help="Dropper Claim ID (Database ID)"
    )
    parser_dropper_get_claim_admin_pool.set_defaults(func=dropper_admin_pool_handler)

    parser_dropper_list_drops = subparsers_dropper.add_parser(
        "list-drops", description="List dropper drops"
    )
    parser_dropper_list_drops.add_argument(
        "-a",
        "--active",
        type=bool,
        required=True,
        help="Claim is active flag",
    )
    parser_dropper_list_drops.add_argument(
        "-c",
        "--dropper-contract-id",
        type=str,
        required=True,
        help="Dropper contract id",
    )
    parser_dropper_list_drops.set_defaults(func=dropper_list_drops_handler)

    parser_dropper_delete_drop = subparsers_dropper.add_parser(
        "delete-drop", description="Delete dropper drop"
    )
    parser_dropper_delete_drop.add_argument(
        "-d",
        "--dropper-claim-id",
        type=str,
        required=True,
        help="Drop id in database",
    )
    parser_dropper_delete_drop.set_defaults(func=dropper_delete_drop_handler)

    parser_dropper_add_claimants = subparsers_dropper.add_parser(
        "add-claimants", description="Add claimants to drop"
    )
    parser_dropper_add_claimants.add_argument(
        "-c",
        "--dropper-claim-id",
        type=str,
        required=True,
        help="Id of particular claim",
    )
    parser_dropper_add_claimants.add_argument(
        "-f",
        "--claimants-file",
        type=str,
        required=True,
        help="Csv of claimants addresses",
    )
    parser_dropper_add_claimants.set_defaults(func=add_claimants_handler)

    parser_dropper_delete_claimants = subparsers_dropper.add_parser(
        "delete-claimants", description="Delete claimants from drop"
    )
    parser_dropper_delete_claimants.add_argument(
        "-c",
        "--dropper-claim-id",
        type=str,
        required=True,
        help="Id of particular claim",
    )
    parser_dropper_delete_claimants.add_argument(
        "-f",
        "--claimants-file",
        type=str,
        required=True,
        help="Csv of claimants addresses",
    )
    parser_dropper_delete_claimants.set_defaults(func=delete_claimants_handler)

    parser_dropper_list_claimants = subparsers_dropper.add_parser(
        "list-claimants", description="List claimants of drop"
    )
    parser_dropper_list_claimants.add_argument(
        "-c", "--dropper-claim-id", type=str, required=True, help="Dropper claim id"
    )
    parser_dropper_list_claimants.set_defaults(func=list_claimants_handler)

    contracts_parser = contracts_actions.generate_cli()
    subparsers_engine_database.add_parser(
        "contracts", parents=[contracts_parser], add_help=False
    )

    args = parser.parse_args()
    args.func(args)


if __name__ == "__main__":
    main()
