# Copyright (c) 2020 The ARA Records Ansible authors
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# See https://github.com/ansible-community/ara/issues/26 for rationale on expiring

import logging
import os
import sys
from datetime import datetime, timedelta

from cliff.command import Command

from ara.cli.base import global_arguments
from ara.clients.utils import get_client


class ExpireObjects(Command):
    """ Expires objects that have been in the running state for too long """

    log = logging.getLogger(__name__)
    expired = 0

    def get_parser(self, prog_name):
        parser = super(ExpireObjects, self).get_parser(prog_name)
        parser = global_arguments(parser)
        # fmt: off
        parser.add_argument(
            "--hours",
            type=int,
            default=24,
            help="Expires objects that have been running state for this many hours (default: 24)"
        )
        parser.add_argument(
            "--order",
            metavar="<order>",
            default="started",
            help=(
                "Orders objects by a field ('id', 'created', 'updated', 'started', 'ended')\n"
                "Defaults to 'started' descending so the oldest objects would be expired first.\n"
                "The order can be reversed by using '-': ara expire --order=-started"
            ),
        )
        parser.add_argument(
            "--limit",
            metavar="<limit>",
            default=os.environ.get("ARA_CLI_LIMIT", 200),
            help=("Only expire the first <limit> determined by the ordering. Defaults to ARA_CLI_LIMIT or 200.")
        )
        parser.add_argument(
            "--confirm",
            action="store_true",
            help="Confirm expiration of objects, otherwise runs without expiring any objects",
        )
        # fmt: on
        return parser

    def take_action(self, args):
        client = get_client(
            client=args.client,
            endpoint=args.server,
            timeout=args.timeout,
            username=args.username,
            password=args.password,
            verify=False if args.insecure else True,
            run_sql_migrations=False,
        )

        if not args.confirm:
            self.log.info("--confirm was not specified, no objects will be expired")

        query = dict(status="running")
        # generate a timestamp from n days ago in a format we can query the API with
        # ex: 2019-11-21T00:57:41.702229
        query["updated_before"] = (datetime.now() - timedelta(hours=args.hours)).isoformat()
        query["order"] = args.order
        query["limit"] = args.limit

        endpoints = ["/api/v1/playbooks", "/api/v1/plays", "/api/v1/tasks"]
        for endpoint in endpoints:
            objects = client.get(endpoint, **query)
            self.log.info("Found %s objects matching query on %s" % (objects["count"], endpoint))
            # TODO: Improve client validation and exception handling
            if "count" not in objects:
                # If we didn't get an answer we can parse, it's probably due to an error 500, 403, 401, etc.
                # The client would have logged the error.
                self.log.error(
                    "Client failed to retrieve results, see logs for ara.clients.offline or ara.clients.http."
                )
                sys.exit(1)

            for obj in objects["results"]:
                link = "%s/%s" % (endpoint, obj["id"])
                if not args.confirm:
                    self.log.info(
                        "Dry-run: %s would have been expired, status is running since %s" % (link, obj["updated"])
                    )
                else:
                    self.log.info("Expiring %s, status is running since %s" % (link, obj["updated"]))
                    client.patch(link, status="expired")
                    self.expired += 1

        self.log.info("%s objects expired" % self.expired)
