from datetime import datetime
import time
import sys
import smtplib
from email.mime.text import MIMEText
import re
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support import expected_conditions as EC

def send_mail(to, subject, body, url, sucess=True):
    try:
        # setup the parameters of the message
        password = "ibogbomqswjaryrs"
        from_addr = "chroion0@gmail.com"
        
        if sucess:
          # Add the URL to the body
          body += f'<br><br><a href="{url}">Room Booking Link</a>'

        # setup the MIME
        msg = MIMEText(body, 'html')  # Change 'plain' to 'html'
        msg['From'] = from_addr
        msg['To'] = to
        msg['Subject'] = subject

        # setup the server
        server = smtplib.SMTP("smtp.gmail.com", 587)
        server.starttls()
        # Add my account login name and password
        server.login(from_addr, password)

        # Send the message via the server
        server.sendmail(from_addr, to, msg.as_string())

        server.quit()

    except Exception as e:
        print("Error: unable to send email", str(e))
        
def attribute_contains(locator, attribute, value):
    """Return the element if its attribute contains the expected value."""
    def predicate(driver):
        element = driver.find_element(*locator)
        return value in element.get_attribute(attribute)
    return predicate

def find_continuous_available_rooms(tbody_data_list, required_days, number_of_person):
    room_availability = {}  # Dictionary to store room availability data
    
    # Parse each item in tbody_data_list
    for data in tbody_data_list:
        # Split by newline to get information for each room type
        room_data_list = data.split('\n')
        
        for room_data in room_data_list:
            if room_data[:3] == "북한산":
                # Use regex to extract the numbers
                match = re.search(r"(북한산 [A-Z]타입)\(적정 (\d+)인 ~ 최대 \d+인\) (\d+) 개", room_data)
            else:
                match = re.search(r"^(.+?)\(.+?(\d+)명\).+?(\d+) 개", room_data)
            
            # Extract the numbers if the regex matched
            if match:
                room_name, minimum_person, available_count = match.groups()
                minimum_person = int(minimum_person)
                available_count = int(available_count)
                
                # Check if the room is suitable for the number of persons
                if minimum_person == number_of_person:
                    # Initialize room name in dictionary if not present
                    if room_name not in room_availability:
                        room_availability[room_name] = []

                    room_availability[room_name].append(available_count)

    # Check for continuous availability
    continuous_available_rooms = []
    for room_name, availability_list in room_availability.items():
        # Check if all days have availability
        if all(count > 0 for count in availability_list[:required_days]):
            continuous_available_rooms.append(room_name)

    return continuous_available_rooms

def get_tbody_data(start_date, end_date, url, place, number_of_person):
    target_start_day = start_date.day - 1
    target_end_day = end_date.day
    diff_month = False
    
    if start_date.month != end_date.month:
        diff_month = True
    
    # Firefox Driver 옵션 설정
    service = Service(executable_path='/var/www/htdocs/find_rooms/python_code/geckodriver')
    firefox_options = Options()
    firefox_options.add_argument("--headless")  # headless 모드 활성화

    driver = webdriver.Firefox(service=service, options=firefox_options)  # geckodriver의 경로를 지정해주세요
    driver.get(url)
    
    mountain_button = driver.find_element(By.XPATH, f"//ul[@class='nav-tabs type2']//a[contains(text(), '{place}')]")
    mountain_button.click()
    
    calendar_cells = driver.find_elements(By.CSS_SELECTOR, ".calendar-cell:not(.disabled):not(.null)")
    tbody_data_list = []
    wait = WebDriverWait(driver, 10)
    
    if diff_month:
        target_calendar_frist = calendar_cells[target_start_day:]
        
        for cell in target_calendar_frist:  # This might need to be adjusted based on target_date.day
            cell.click()
            
            # Use our custom expected condition
            wait.until(attribute_contains((By.TAG_NAME, "body"), "class", "overflow-hidden"))

            tbody_element = driver.find_element(By.CSS_SELECTOR, "#livingRoom .tbody")
            tbody_text = tbody_element.text
            tbody_data_list.append(tbody_text)
            driver.find_element(By.CSS_SELECTOR, ".btn-confirm.is-active").click()        
        
        next_month_button = driver.find_element(By.CSS_SELECTOR, "a.btn-next")
        next_month_button.click()
        
        # Wait for the calendar title's month span to change to the expected month
        expected_month_text = f"{str(end_date.month).zfill(2)}월"
        
        WebDriverWait(driver, 10).until(
            EC.text_to_be_present_in_element((By.CSS_SELECTOR, ".calendar-title span:nth-child(2)"), expected_month_text)
        )
        
        calendar_cells = driver.find_elements(By.CSS_SELECTOR, ".calendar-cell:not(.disabled):not(.null)")
        target_calendar_second = calendar_cells[:target_end_day]

        for cell in target_calendar_second:  # This might need to be adjusted based on target_date.day
            cell.click()
            
            # Use our custom expected condition
            wait.until(attribute_contains((By.TAG_NAME, "body"), "class", "overflow-hidden"))

            tbody_element = driver.find_element(By.CSS_SELECTOR, "#livingRoom .tbody")
            tbody_text = tbody_element.text
            tbody_data_list.append(tbody_text)
            driver.find_element(By.CSS_SELECTOR, ".btn-confirm.is-active").click()                  
        
    else:
        target_calendar = calendar_cells[target_start_day:target_end_day]

        for cell in target_calendar:  # This might need to be adjusted based on target_date.day
            cell.click()
            
            # Use our custom expected condition
            wait.until(attribute_contains((By.TAG_NAME, "body"), "class", "overflow-hidden"))

            tbody_element = driver.find_element(By.CSS_SELECTOR, "#livingRoom .tbody")
            tbody_text = tbody_element.text
            tbody_data_list.append(tbody_text)
            driver.find_element(By.CSS_SELECTOR, ".btn-confirm.is-active").click()
    
    driver.quit()
    
    # Find continuous available rooms
    required_days = (end_date - start_date).days + 1
    available_rooms = find_continuous_available_rooms(tbody_data_list, required_days, number_of_person)
    
    return available_rooms

if __name__ == "__main__":
    ecology_option = sys.argv[1]
    start_date = datetime.strptime(sys.argv[2], "%Y-%m-%d")
    end_date = datetime.strptime(sys.argv[3], "%Y-%m-%d")
    url = "https://reservation.knps.or.kr/eco/searchEcoMonthReservation.do"
    number_of_person = int(sys.argv[4])    

    ecology_option_map = {
                    "bukhansan": "북한산",
                    "jirisan": "지리산",
                    "sobaeksan": "소백산",
                    "seoraksan": "설악산",
                    "hanryohaesang": "한려해상",
                    "mudeungsan": "무등산",
                    "gayasan": "가야산",
                    "naejangsan": "내장산",
                    "byunsanbando": "변산반도"
                }
    
    place = ecology_option_map.get(ecology_option)

    while True:
        available_rooms = get_tbody_data(start_date, end_date, url, place, number_of_person)
        if available_rooms: 
            to = "chroion0@gmail.com"  
            subject = "생태원 빈방 알림"
            body = f"{start_date.date()} ~ {end_date.date()} 까지의 빈방 목록 <br>"
            body += "<br>".join(["<br>" + room for room in available_rooms])
            send_mail(to, subject, body, url)
            break  
            
        else:
            current_date = datetime.now().date()
            if start_date.date() <= current_date:
                to = "chroion0@gmail.com"
                subject = "빈방 검색 종료 알림"
                body = f"예약하셨던 생태원 사이트에서의 {place}의 {start_date.date()} ~ {end_date.date()} 까지의 빈방이 없어서 검색이 종료되었기에 알려드립니다."
                send_mail(to, subject, body, url, False)
                break
            
            time.sleep(600)
