#! /usr/bin/env python3
#
# BitBake Toaster Implementation
#
# Copyright (C) 2013-2016 Intel Corporation
#
# SPDX-License-Identifier: GPL-2.0-only
#

from datetime import datetime
import os

from django.urls import reverse
from django.utils import timezone
from tests.browser.selenium_helpers import SeleniumTestCase
from orm.models import BitbakeVersion, Release, Project, Build
from selenium.webdriver.common.by import By

class TestToasterTableUI(SeleniumTestCase):
    """
    Tests for the UI elements of ToasterTable (sorting etc.);
    note that the tests cover generic functionality of ToasterTable which
    manifests as UI elements in the browser, and can only be tested via
    Selenium.
    """

    def setUp(self):
        pass

    def _get_orderby_heading(self, table):
        """
        Get the current order by finding the column heading in <table> with
        the sorted class on it.

        table: WebElement for a ToasterTable
        """
        selector = 'thead a.sorted'
        heading = table.find_element(By.CSS_SELECTOR, selector)
        return heading.get_attribute('innerHTML').strip()

    def _get_datetime_from_cell(self, row, selector):
        """
        Return the value in the cell selected by <selector> on <row> as a
        datetime.

        row: <tr> WebElement for a row in the ToasterTable
        selector: CSS selector to use to find the cell containing the date time
        string
        """
        cell = row.find_element(By.CSS_SELECTOR, selector)
        cell_text = cell.get_attribute('innerHTML').strip()
        return datetime.strptime(cell_text, '%d/%m/%y %H:%M')

    def test_revert_orderby(self):
        """
        Test that sort order for a table reverts to the default sort order
        if the current sort column is hidden.
        """
        now = timezone.now()
        later = now + timezone.timedelta(hours=1)
        even_later = later + timezone.timedelta(hours=1)

        builldir = os.environ.get('BUILDDIR', './')
        bbv = BitbakeVersion.objects.create(name='test bbv', giturl=f'{builldir}/',
                                            branch='master', dirpath='')
        release = Release.objects.create(name='test release',
                                         branch_name='master',
                                         bitbake_version=bbv)

        project = Project.objects.create_project('project', release)

        # set up two builds which will order differently when sorted by
        # started_on or completed_on

        # started first, finished last
        build1 = Build.objects.create(project=project,
                                      started_on=now,
                                      completed_on=even_later,
                                      outcome=Build.SUCCEEDED)

        # started second, finished first
        build2 = Build.objects.create(project=project,
                                      started_on=later,
                                      completed_on=later,
                                      outcome=Build.SUCCEEDED)

        url = reverse('all-builds')
        self.get(url)
        table = self.wait_until_visible('#allbuildstable')

        # check ordering (default is by -completed_on); so build1 should be
        # first as it finished last
        active_heading = self._get_orderby_heading(table)
        self.assertEqual(active_heading, 'Completed on',
            'table should be sorted by "Completed on" by default')

        row_selector = '#allbuildstable tbody tr'
        cell_selector = 'td.completed_on'

        rows = self.find_all(row_selector)
        row1_completed_on = self._get_datetime_from_cell(rows[0], cell_selector)
        row2_completed_on = self._get_datetime_from_cell(rows[1], cell_selector)
        self.assertTrue(row1_completed_on > row2_completed_on,
            'table should be sorted by -completed_on')

        # turn on started_on column
        self.click('#edit-columns-button')
        self.click('#checkbox-started_on')

        # sort by started_on column
        links = table.find_elements(By.CSS_SELECTOR, 'th.started_on a')
        for link in links:
            if link.get_attribute('innerHTML').strip() == 'Started on':
                link.click()
                break

        # wait for table data to reload in response to new sort
        self.wait_until_visible('#allbuildstable')

        # check ordering; build1 should be first
        active_heading = self._get_orderby_heading(table)
        self.assertEqual(active_heading, 'Started on',
            'table should be sorted by "Started on"')

        cell_selector = 'td.started_on'

        rows = self.find_all(row_selector)
        row1_started_on = self._get_datetime_from_cell(rows[0], cell_selector)
        row2_started_on = self._get_datetime_from_cell(rows[1], cell_selector)
        self.assertTrue(row1_started_on < row2_started_on,
            'table should be sorted by started_on')

        # turn off started_on column
        self.click('#edit-columns-button')
        self.click('#checkbox-started_on')

        # wait for table data to reload in response to new sort
        self.wait_until_visible('#allbuildstable')

        # check ordering (should revert to completed_on); build2 should be first
        active_heading = self._get_orderby_heading(table)
        self.assertEqual(active_heading, 'Completed on',
            'table should be sorted by "Completed on" after hiding sort column')

        cell_selector = 'td.completed_on'

        rows = self.find_all(row_selector)
        row1_completed_on = self._get_datetime_from_cell(rows[0], cell_selector)
        row2_completed_on = self._get_datetime_from_cell(rows[1], cell_selector)
        self.assertTrue(row1_completed_on > row2_completed_on,
            'table should be sorted by -completed_on')
