# Copyright 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Library for frontend.afe.models.JobHandoff and job cleanup."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import datetime
import logging
import socket

from lucifer import autotest

logger = logging.getLogger(__name__)


_JOB_GRACE_SECS = 10


def incomplete():
    """Return a QuerySet of incomplete JobHandoffs.

    JobHandoff created within a cutoff period are exempt to allow the
    job the chance to acquire its lease file; otherwise, incomplete jobs
    without an active lease are considered dead.

    @returns: Django QuerySet
    """
    models = autotest.load('frontend.afe.models')
    Q = autotest.deps_load('django.db.models').Q
    # Time ---*---------|---------*-------|--->
    #    incomplete   cutoff   newborn   now
    cutoff = (datetime.datetime.now()
              - datetime.timedelta(seconds=_JOB_GRACE_SECS))
    return (models.JobHandoff.objects
            .filter(completed=False, created__lt=cutoff)
            .filter(Q(drone=socket.gethostname()) | Q(drone=None)))


def clean_up(job_ids):
    """Clean up failed jobs failed in database.

    This brings the database into a clean state, which includes marking
    the job, HQEs, and hosts.
    """
    if not job_ids:
        return
    models = autotest.load('frontend.afe.models')
    logger.info('Cleaning up failed jobs: %r', job_ids)
    hqes = models.HostQueueEntry.objects.filter(job_id__in=job_ids)
    logger.debug('Cleaning up HQEs: %r', hqes.values_list('id', flat=True))
    _clean_up_hqes(hqes)
    host_ids = {id for id in hqes.values_list('host_id', flat=True)
                if id is not None}
    logger.debug('Found Hosts associated with jobs: %r', host_ids)
    _clean_up_hosts(host_ids)


def _clean_up_hqes(hqes):
    models = autotest.load('frontend.afe.models')
    logger.debug('Cleaning up HQEs: %r', hqes.values_list('id', flat=True))
    hqes.update(complete=True,
                active=False,
                status=models.HostQueueEntry.Status.FAILED)
    (hqes.exclude(started_on=None)
     .update(finished_on=datetime.datetime.now()))


def _clean_up_hosts(host_ids):
    models = autotest.load('frontend.afe.models')
    transaction = autotest.deps_load('django.db.transaction')
    with transaction.commit_on_success():
        active_hosts = {
            id for id in (models.HostQueueEntry.objects
                          .filter(active=True, complete=False)
                          .values_list('host_id', flat=True))
            if id is not None}
        logger.debug('Found active Hosts: %r', active_hosts)
        (models.Host.objects
         .filter(id__in=host_ids)
         .exclude(id__in=active_hosts)
         .update(status=models.Host.Status.READY))


def mark_complete(job_ids):
    """Mark the corresponding JobHandoffs as completed."""
    if not job_ids:
        return
    models = autotest.load('frontend.afe.models')
    logger.info('Marking job handoffs complete: %r', job_ids)
    (models.JobHandoff.objects
     .filter(job_id__in=job_ids)
     .update(completed=True))
