#!/usr/bin/env python3
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.

import json
from argparse import ArgumentParser, Namespace

from idb.cli.commands.base import TargetCommand
from idb.client.client import IdbClient
from idb.common.types import CrashLogQuery


class CrashDeleteException(Exception):
    pass


def _add_query_arguments(parser: ArgumentParser) -> None:
    parser.add_argument(
        "--before", help="Match based older than the provided unix timestamp", type=int
    )
    parser.add_argument(
        "--since",
        help="Match based on being newer than the provided unix timestamp",
        type=int,
    )
    parser.add_argument(
        "--bundle-id",
        help="Filter based on the bundle id of the crashed process",
        type=str,
    )


def _build_query(arguments: Namespace) -> CrashLogQuery:
    if (
        hasattr(arguments, "all")
        and not arguments.all
        and hasattr(arguments, "name")
        and not arguments.name
        and arguments.before is None
        and arguments.since is None
        and arguments.bundle_id is None
    ):
        raise CrashDeleteException("Must pass --all if not other arguments specified")

    return CrashLogQuery(
        before=arguments.before,
        since=arguments.since,
        bundle_id=arguments.bundle_id,
        name=getattr(arguments, "name", None),
    )


class CrashListCommand(TargetCommand):
    @property
    def description(self) -> str:
        return "List the available crashes"

    @property
    def name(self) -> str:
        return "list"

    def add_parser_arguments(self, parser: ArgumentParser) -> None:
        _add_query_arguments(parser=parser)
        super().add_parser_arguments(parser)

    async def run_with_client(self, args: Namespace, client: IdbClient) -> None:
        crashes = await client.crash_list(query=_build_query(args))
        for crash in crashes:
            print(json.dumps(crash._asdict()))


class CrashShowCommand(TargetCommand):
    @property
    def description(self) -> str:
        return "Fetch a crash log"

    @property
    def name(self) -> str:
        return "show"

    def add_parser_arguments(self, parser: ArgumentParser) -> None:
        parser.add_argument("name", help="The unique name of the crash")
        super().add_parser_arguments(parser)

    async def run_with_client(self, args: Namespace, client: IdbClient) -> None:
        crash = await client.crash_show(name=args.name)
        print(crash.contents)


class CrashDeleteCommand(TargetCommand):
    @property
    def description(self) -> str:
        return "Delete a crash log"

    @property
    def name(self) -> str:
        return "delete"

    def add_parser_arguments(self, parser: ArgumentParser) -> None:
        parser.add_argument(
            "name", nargs="?", default=None, help="The unique name of the crash"
        )
        _add_query_arguments(parser=parser)
        parser.add_argument("--all", help="Delete all crash logs", action="store_true")
        super().add_parser_arguments(parser)

    async def run_with_client(self, args: Namespace, client: IdbClient) -> None:
        crashes = await client.crash_delete(query=_build_query(args))
        for crash in crashes:
            print(json.dumps(crash._asdict()))
