#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

from dataclasses import dataclass

from selenium.common import exceptions
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait


@dataclass
class TableDefinition:
    """Class for keeping track of fields on the page"""
    next: bool
    prev: bool
    count: int
    names: list


def get_and_dismiss_messages(driver, config):
    messages = WebDriverWait(driver, config.selenium.message_wait).until(
        EC.presence_of_all_elements_located(
            (By.CSS_SELECTOR, 'div.messages div.alert')))
    collect = []
    for message in messages:
        text = message.find_element(By.CSS_SELECTOR, "p, div").text
        message.find_element(By.CSS_SELECTOR, "a.close").click()
        collect.append(text)
    return collect


def find_already_visible_element_by_xpath(element, driver):
    return WebDriverWait(driver, 160).until(
        EC.visibility_of_element_located((By.XPATH, element)))


def select_from_dropdown(element, label):
    menu_button = element.find_element(By.CSS_SELECTOR, ".dropdown-toggle")
    menu_button.click()
    options = element.find_element(By.CSS_SELECTOR, "ul.dropdown-menu")
    selection = options.find_element(
        By.XPATH, f".//*[normalize-space()='{label}']")
    selection.click()


def select_from_specific_dropdown_in_form(driver, dropdown_id, label):
    dropdown = driver.find_element(
        By.XPATH,
        f".//*[@for='{dropdown_id}']/following-sibling::div")  # noqa: E231
    dropdown.click()
    dropdown_options = dropdown.find_element(
        By.CSS_SELECTOR, "ul.dropdown-menu")
    dropdown_options.find_element(
        By.XPATH, f".//*[normalize-space()='{label}']").click()


def confirm_modal(element):
    confirm = element.find_element(By.CSS_SELECTOR, ".modal-dialog .btn-danger")
    confirm.click()


def is_next_link_available(driver):
    try:
        return driver.find_element(By.LINK_TEXT, "Next »").is_displayed()
    except (exceptions.NoSuchElementException,
            exceptions.ElementNotVisibleException):
        return False


def is_prev_link_available(driver):
    try:
        return driver.find_element(By.LINK_TEXT, "« Prev").is_displayed()
    except (exceptions.NoSuchElementException,
            exceptions.ElementNotVisibleException):
        return False


def available_elements(driver, resource_type, name):
    try:
        driver.find_elements(
            By.CSS_SELECTOR, f"table#{resource_type} tr[data-display='{name}']")
    except (exceptions.NoSuchElementException):
        pass
    finally:
        return driver.find_elements(
            By.CSS_SELECTOR, 'table tr td:nth-child(2) a')


def get_table_status(driver, resource_type, name, sorting=False):
    elements = available_elements(driver, resource_type, name)
    if sorting:
        names = [name.text for name in elements]
        names.sort()
    actual_table = TableDefinition(next=is_next_link_available(driver),
                                   prev=is_prev_link_available(driver),
                                   count=len(elements), names=[names[0]])
    return actual_table


def get_image_table_definition(driver, sorting=False):
    """This function is specific to Image table definition"""
    names = driver.find_elements(
        By.CSS_SELECTOR, "td[class='rsp-p1 word-wrap']")
    if sorting:
        names = [name.text for name in names]
        names.sort()

    actual_table = TableDefinition(next=is_next_link_available(driver),
                                   prev=is_prev_link_available(driver),
                                   count=len(names), names=[names[0]])
    return actual_table


def select_from_transfer_table(element, label):
    try:
        element.find_element(
            By.XPATH,
            f".//*[text()='{label}']//ancestor::tr/td//*"  # noqa: E231
            f"[@class='btn btn-default fa fa-arrow-up']").click()
    except exceptions.NoSuchElementException:
        try:
            element.find_element(
                By.XPATH,
                f".//*[text()='{label}']//ancestor::tr/td//*"  # noqa: E231
                f"[@class='btn btn-default fa fa-arrow-down']")
        except exceptions.NoSuchElementException:
            raise
