"""Модуль компонента средства выбора даты.

Содержит класс для работы с средством выбора даты через Playwright.
"""

import datetime
from playwright.sync_api import Page
from tools.logger import get_logger
from locators.date_picker_locators import DatePickerLocators
from elements.text_element import Text
from elements.button_element import Button
from components.base_component import BaseComponent

logger = get_logger("DATE_PICKER")


class DatePickerComponent(BaseComponent):
    """Компонент средства выбора даты.

    Предоставляет методы для взаимодействия с элементами средства выбора даты.
    """

    def __init__(self, page: Page):
        """Инициализирует компонент средства выбора даты.

        Args:
            page: Экземпляр страницы Playwright.
        """

        super().__init__(page)

        self.date_picker_year_button = Button(page,
                                     DatePickerLocators.DATE_PICKER_TITLE_BUTTON_YEAR,
                                     "date_picker_year_button")

        loc = page.locator(DatePickerLocators.DATE_PICKER_HEADER).\
              get_by_role("button").locator("i.mdi-chevron-left")
        self.prev_month_button = Button(page, loc, "prev_month_button")

        loc = page.locator(DatePickerLocators.DATE_PICKER_HEADER).\
              get_by_role("button").locator("i.mdi-chevron-right")
        self.next_month_button = Button(page, loc, "next_month_button")

        self.current_month_year = Text(page,
                                     DatePickerLocators.DATE_PICKER_HEADER_VALUE,
                                     "current_month_year")

    # Действия:
    def click_prev_month_button(self) -> None:
        """ Нажатие на кнопку перехода к предыдущему месяцу (стрелочка влево)."""

        self.prev_month_button.click()

    def click_next_month_button(self) -> None:
        """ Нажатие на кнопку перехода к следующему месяцу (стрелочка вправо)."""

        self.next_month_button.click()

    def click_year_button(self) -> None:
        """ Нажатие на кнопку текущего значения года в заголовке средства выбора даты."""

        self.date_picker_year_button.click()

    def get_year(self) -> str:
        """ Получение текущего значения года из заголовка средства выбора даты."""

        return self.date_picker_year_button.get_text(0).strip()

    def get_month_year(self) -> str:
        """ Получение текущего значения месяца и года."""

        return self.current_month_year.get_text(0).strip()

    def get_day(self) -> str:
        """ Получение текущего номера дня."""

        days_table_locator = self.page.locator(DatePickerLocators.DATE_PICKER_TABLE_DAYS)
        day_button_locator = days_table_locator.locator("//td/button[contains(@class, 'accent--text')]")

        return day_button_locator.text_content().strip()

    def select_day(self, day: str) -> None:
        """ Выбор дня месяца по его номеру."""

        visible = False

        days_table_locator = self.page.locator(DatePickerLocators.DATE_PICKER_TABLE_DAYS)
        days_table_locator.wait_for(timeout=300)
        day_button_locator = days_table_locator.locator("//td").get_by_role("button", name=day)
        visible = day_button_locator.is_visible()
        if visible:
            day_button_locator.click()
        else:
            assert False, f"Day number {day} is missing on date picker days table"

    def select_year_and_month(self, year: str, month: str) -> None:
        """ Выбор года и месяца по заданным значениям. Значения должны быть в формате гггг и мм"""

        try:
            month_index = int(month)
        except ValueError:
            assert False, f"Incorrect month value {month} for selection"

        assert month_index >= 1, f"Incorrect month value {month} for selection"
        assert month_index <= 12, f"Incorrect month value {month} for selection"

        current_year = int(self.get_year())
        if int(year) > current_year + 100 or int(year) < current_year - 100:
            assert False, f"Incorrect year value {year} for selection"

        self.click_year_button()

        years_list = self.page.locator(DatePickerLocators.DATE_PICKER_LIST_YEARS)
        years_list.wait_for(timeout=300)
        year_locator = f"{DatePickerLocators.DATE_PICKER_LIST_YEARS} li:has-text(\"{year}\")"
        self.page.locator(year_locator).click()

        months_table = self.page.locator(DatePickerLocators.DATE_PICKER_TABLE_MONTHS)
        months_table.wait_for(timeout=300)
        month_button = months_table.locator("//td").get_by_role("button").nth(month_index-1)
        month_button.click()


    # Проверки:
    def check_prev_month_button_visibility(self) -> None:
        """ Проверка видимости кнопки перехода к предыдущему месяцу (стрелочка влево)."""

        self.prev_month_button.check_visibility("Prev Month Button is missing")

    def check_next_month_button_visibility(self) -> None:
        """ Проверка видимости кнопки перехода к следующему месяцу (стрелочка вправо)."""

        self.next_month_button.check_visibility("Next Month Button is missing")

    def check_year_button_visibility(self) -> None:
        """ Проверка видимости кнопки текущего значения года в заголовке средства выбора даты."""

        self.date_picker_year_button.check_visibility("Current Year Button is missing")

    def check_content(self) -> None:
        """Проверка состава компонент средства выбора даты."""

        month_dict = {"1":"январь",
                      "2":"февраль",
                      "3":"март",
                      "4":"апрель",
                      "5":"май",
                      "6":"июнь",
                      "7":"июль",
                      "8":"август",
                      "9":"сентябрь",
                      "10":"октябрь",
                      "11":"ноябрь",
                      "12":"декабрь"}
        days_per_month = {"1":31,
                          "2":28,
                          "3":31,
                          "4":30,
                          "5":31,
                          "6":30,
                          "7":31,
                          "8":31,
                          "9":30,
                          "10":31,
                          "11":30,
                          "12":31}
        expected_weekdays = ["В", "П", "В", "С", "Ч", "П", "С"]

        expected_date = datetime.datetime.now()

        # Проверка наличия кнопки текущего значения года в заголовке средства выбора даты
        self.check_year_button_visibility()

        actual_year = self.get_year()
        assert actual_year == str(expected_date.year), \
            f"Expected year {expected_date.year} is not equal actual year {actual_year} on date picker title"

        # Проверка наличия кнопок перехода к предыдущему/следующему месяцу
        self.check_prev_month_button_visibility()
        self.check_next_month_button_visibility()

        # Проверка наличия и правильности текущей даты
        self.current_month_year.check_visibility("Month and Year values is missing on date picker body")

        y = expected_date.year
        m = str(expected_date.strftime("%m"))
        expected_month_year = f"{month_dict[m]} {y} г."
        actual_month_year = self.get_month_year()
        assert actual_month_year == expected_month_year, \
            f"Expected value {expected_month_year} is not equal actual value {actual_month_year} on date picker body"

        expected_day = str(expected_date.strftime("%d"))
        actual_day = self.get_day()
        assert actual_day == expected_day, \
            f"Expected day {expected_day} is not equal actual day {actual_day} on date picker body"

        # Проверка таблицы дней
        days_table_locator = self.page.locator(DatePickerLocators.DATE_PICKER_TABLE_DAYS)
        headers = days_table_locator.locator("th").all()
        actual_weekdays = []
        for header in headers:
            actual_weekdays.append(header.text_content())

        assert actual_weekdays == expected_weekdays, \
            f"Expected weekdays list {expected_weekdays} is not equal actual weekdays list {actual_weekdays} on date picker body"

        rows = days_table_locator.locator("//tbody/tr")
        days_counter = 0
        for i in range(rows.count()):
            row = rows.nth(i)
            cells = row.locator("td")
            for j in range(cells.count()):
                cell_text = cells.nth(j).inner_text()
                if cell_text != "":
                    days_counter += 1

        expected_day_counter = days_per_month[m]
        if m == "2" and self._is_leap_year(expected_date.year):
            expected_day_counter = 29

        assert days_counter == expected_day_counter, f"Incorrect amount of days {days_counter} on date picker body"

    def _is_leap_year(self, year: str) -> bool:
        """Проверка является ли год високосным."""

        if int(year) % 400 == 0:
            return True
        if int(year) % 100 == 0:
            return False
        if int(year) % 4 == 0:
            return True
        return False
