import time
from datetime import datetime

from bs4 import BeautifulSoup
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select
from selenium.webdriver.support.wait import WebDriverWait

from uk_bin_collection.uk_bin_collection.common import *
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass

# import the wonderful Beautiful Soup and the URL grabber


class CouncilClass(AbstractGetBinDataClass):
    """
    Concrete classes have to implement all abstract operations of the
    base class. They can also override some operations with a default
    implementation.
    """

    def parse_data(self, page: str, **kwargs) -> dict:
        """
        Retrieve bin collection dates for a property from Halton Council's waste service.
        
        This method loads the council's waste service page, submits the provided property identifier and postcode, parses the resulting collection schedule, and returns structured bin collection entries.
        
        Parameters:
            paon (str, via kwargs): Property identifier — house number or property name.
            postcode (str, via kwargs): Property postcode.
            web_driver (str or selenium.webdriver, via kwargs): Optional webdriver backend identifier or instance passed to create_webdriver.
            headless (bool, via kwargs): If True, the browser is created in headless mode.
        
        Returns:
            dict: A dictionary with a single key "bins" containing a list of collection entries. Each entry is a dict with:
                - "type" (str): Waste type name (capitalized).
                - "collectionDate" (str): Collection date formatted as "DD/MM/YYYY".
        """
        driver = None
        try:
            data = {"bins": []}

            user_paon = kwargs.get("paon")
            user_postcode = kwargs.get("postcode")
            web_driver = kwargs.get("web_driver")
            headless = kwargs.get("headless")
            # Create Selenium webdriver
            page = (
                f"https://webapp.halton.gov.uk/PublicWebForms/WasteServiceSearchv1.aspx"
            )

            user_agent = "Mozilla/5.0 (Windows NT 6.1; Win64; x64)"

            driver = create_webdriver(web_driver, headless, user_agent, __name__)
            driver.get(page)

            # If you bang in the house number (or property name) and postcode in the box it should find your property

            # iframe_presense = WebDriverWait(driver, 30).until(
            #    EC.presence_of_element_located((By.ID, "fillform-frame-1"))
            # )

            # driver.switch_to.frame(iframe_presense)
            wait = WebDriverWait(driver, 60)

            inputElement_property = wait.until(
                EC.element_to_be_clickable(
                    (By.NAME, "ctl00$ContentPlaceHolder1$txtProperty")
                )
            )
            inputElement_property.send_keys(user_paon)

            inputElement_postcodesearch = wait.until(
                EC.element_to_be_clickable(
                    (By.NAME, "ctl00$ContentPlaceHolder1$txtPostcode")
                )
            )
            inputElement_postcodesearch.send_keys(user_postcode)
            time.sleep(1)
            wait.until(
                EC.frame_to_be_available_and_switch_to_it(
                    (
                        By.CSS_SELECTOR,
                        "iframe[name^='a-'][src^='https://www.google.com/recaptcha/api2/anchor?']",
                    )
                )
            )
            wait.until(
                EC.element_to_be_clickable((By.XPATH, "//span[@id='recaptcha-anchor']"))
            ).send_keys(Keys.ENTER)
            time.sleep(5)
            driver.switch_to.default_content()
            search_btn = wait.until(
                EC.element_to_be_clickable(
                    (By.XPATH, '//*[@id="ContentPlaceHolder1_btnSearch"]')
                )
            )
            search_btn.send_keys(Keys.ENTER)
            WebDriverWait(driver, 10).until(
                EC.presence_of_element_located((By.ID, "collectionTabs"))
            )

            soup = BeautifulSoup(driver.page_source, features="html.parser")

            # Find all tab panels within the collectionTabs
            # Find all anchor elements within the collectionTabs
            anchor_elements = soup.select("#collectionTabs a.ui-tabs-anchor")

            for anchor in anchor_elements:
                # Extract the type of waste from the anchor text
                waste_type = anchor.text.strip()

                # Find the corresponding panel using the href attribute
                panel_id = anchor.get("href")
                panel = soup.select_one(panel_id)

                # Find all ul elements within the corresponding panel
                ul_elements = panel.find_all("ul")

                # Check if there are at least two ul elements
                if len(ul_elements) >= 2:
                    # Get the second ul element and extract its li elements
                    second_ul = ul_elements[1]
                    li_elements = second_ul.find_all("li")

                    # Extract the text content of each li element
                    date_texts = [
                        re.sub(r"[^a-zA-Z0-9,\s]", "", li.get_text(strip=True)).strip()
                        for li in li_elements
                    ]

                    for date_text in date_texts:
                        # Extracting dates from the text using simple text manipulation
                        # Assuming the dates are in the format: "Friday 15th December 2023", "Friday 22nd December 2023", etc.
                        # Parse the date string into a datetime object
                        date_string_without_ordinal = re.sub(
                            r"(\d+)(st|nd|rd|th)", r"\1", date_text
                        )

                        parsed_date = datetime.strptime(
                            date_string_without_ordinal, "%A %d %B %Y"
                        )

                        # Format the datetime object into the desired format '%d/%m/%Y'
                        formatted_date = parsed_date.strftime("%d/%m/%Y")

                        # Add extracted data to the 'bins' list
                        data["bins"].append(
                            {
                                "type": waste_type.capitalize(),
                                "collectionDate": formatted_date,
                            }
                        )
        except Exception as e:
            # Here you can log the exception if needed
            print(f"An error occurred: {e}")
            # Optionally, re-raise the exception if you want it to propagate
            raise
        finally:
            # This block ensures that the driver is closed regardless of an exception
            if driver:
                driver.quit()
        return data