# This script pulls (in one hit) the data from Bromley Council Bins Data
import datetime
import re
import time
from datetime import datetime

import requests
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:
        driver = None
        try:
            uprn = kwargs.get("uprn")
            postcode = kwargs.get("postcode")
            full_address = kwargs.get("paon")

            url = "https://my.guildford.gov.uk/customers/s/view-bin-collections"

            web_driver = kwargs.get("web_driver")
            headless = kwargs.get("headless")

            driver = create_webdriver(web_driver, headless, None, __name__)
            driver.get(kwargs.get("url"))

            wait = WebDriverWait(driver, 120)
            post_code_search = wait.until(
                EC.presence_of_element_located(
                    (By.XPATH, "//input[contains(@class, 'slds-input')]")
                )
            )

            post_code_search.send_keys(postcode)

            post_code_submit_btn = wait.until(
                EC.presence_of_element_located(
                    (By.XPATH, "//button[contains(@class,'slds-button')]")
                )
            )
            post_code_submit_btn.send_keys(Keys.ENTER)

            # Locate the element containing the specified address text
            address_element = WebDriverWait(driver, 10).until(
                EC.presence_of_element_located(
                    (
                        By.XPATH,
                        f"//lightning-base-formatted-text[contains(text(), '{full_address}')]",
                    )
                )
            )

            # Find the associated radio button in the same row (preceding sibling)
            radio_button = address_element.find_element(
                By.XPATH, "../../../../preceding-sibling::td//input[@type='radio']"
            )

            radio_button.send_keys(Keys.SPACE)
            address_submit_btn = wait.until(
                EC.presence_of_element_located(
                    (By.XPATH, "//button[contains(@name,'NEXT')]")
                )
            )
            address_submit_btn.send_keys(Keys.ENTER)

            results = wait.until(
                EC.presence_of_element_located((By.CLASS_NAME, "cBinScheduleDisplay"))
            )

            results2 = wait.until(
                EC.presence_of_element_located(
                    (By.XPATH, f'//div[contains(@title,"Bin Job")]')
                )
            )
            soup = BeautifulSoup(driver.page_source, features="html.parser")
            # Find all table rows containing bin information
            rows = soup.find_all("tr", class_="slds-hint-parent")

            data = {"bins": []}

            # Extract bin type and next collection date for each row
            for row in rows:
                bin_type = (
                    row.find("td", {"data-label": "Bin Job"})
                    .find("strong")
                    .text.strip()
                    if row.find("td", {"data-label": "Bin Job"})
                    else None
                )

                next_collection_date = (
                    row.find("td", {"data-label": "Next Collection"}).text.strip()
                    if row.find("td", {"data-label": "Next Collection"})
                    else None
                )

                if bin_type and next_collection_date:
                    # Convert date string to datetime object
                    date_format = (
                        "%A, %d %B"  # Adjust the format according to your date string
                    )
                    try:
                        next_collection_date = datetime.strptime(
                            next_collection_date, date_format
                        )

                        # Logic to determine year
                        current_date = datetime.now()
                        if next_collection_date.month < current_date.month:
                            year = current_date.year + 1
                        else:
                            year = current_date.year

                        # Format the date
                        next_collection_date = next_collection_date.replace(
                            year=year
                        ).strftime("%d/%m/%Y")
                    except ValueError:
                        pass

                    dict_data = {
                        "type": bin_type,
                        "collectionDate": next_collection_date,
                    }
                    data["bins"].append(dict_data)
        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
