import urllib.request
from bs4 import BeautifulSoup
from datetime import datetime, timedelta
import time
import sys
import smtplib
from email.mime.text import MIMEText
import re

def get_page_title(url):
    req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
    with urllib.request.urlopen(req) as response:
        webpage = response.read()
        soup = BeautifulSoup(webpage, 'html.parser')
        return soup.title.string

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 find_available_rooms(start_date, end_date, urls):    
    all_available_rooms = []
    
    for i,url in enumerate(urls):
        if i==0:
          year = start_date.year
          month = start_date.month
        elif i==1:
          year = end_date.year
          month = end_date.month        
    
        req = urllib.request.Request(url)
        data = urllib.request.urlopen(req).read()

        soup = BeautifulSoup(data, 'html.parser')

        thead = soup.find('thead')
        tbody = soup.find('tbody')

        # Parse the data
        dates = [th.text for th in thead.find_all('th')][1:]  # First th is for date column, so we skip it
        for tr in tbody.find_all('tr'):
            room = tr.find('th').text
            for td, date in zip(tr.find_all('td'), dates):
                img = td.find('img', class_='state-icon')
                if img and img['alt'] == '예약가능':  # If there is an image with 'state-icon' class and its alt attribute is '예약가능', the room is available
                    available_date = datetime.strptime(f"{year}/{month}/{date[0:-1]}", '%Y/%m/%d')
                    all_available_rooms.append((available_date, room))
    
    # Collect available dates for each room
    available_dates = {}
    for date, room in all_available_rooms:
        if room not in available_dates:
            available_dates[room] = []
        available_dates[room].append(date)
    
    # Convert the dates to datetime objects and sort the dates
    for room in available_dates:
        valid_dates = [date for date in available_dates[room]]
        available_dates[room] = sorted(valid_dates)
    
    # Find continuous available dates for each room
    continuous_dates = {}
    for room, dates in available_dates.items():
        continuous_dates[room] = []  # Initialize the list for the room
        start_date_room = dates[0]
        end_date_room = dates[0]
        for date in dates[1:]:
            if date - end_date_room == timedelta(days=1):  # If the date is the next day
                end_date_room = date
            else:  # If the date is not the next day
                continuous_dates[room].append((start_date_room.strftime("%Y/%m/%d"), end_date_room.strftime("%Y/%m/%d")))  # Add the continuous dates to the list
                start_date_room = date
                end_date_room = date
        continuous_dates[room].append((start_date_room.strftime("%Y/%m/%d"), end_date_room.strftime("%Y/%m/%d")))  # Add the last continuous dates to the list
    
    # Convert user's start_date and end_date to datetime objects
    start_date = start_date.date()
    end_date = end_date.date()

    # Find the rooms that are available continuously during the user's period
    available_rooms_during_period = []
    for room, dates in continuous_dates.items():
        for start_date_range, end_date_range in dates:
            start_date_range = datetime.strptime(start_date_range, "%Y/%m/%d")
            end_date_range = datetime.strptime(end_date_range, "%Y/%m/%d")
            if start_date_range.date() <= start_date and end_date <= end_date_range.date():  # If the room is available during the user's period
                available_rooms_during_period.append(room)
                break  # No need to check other date ranges for this room
    
    return available_rooms_during_period

if __name__ == "__main__":
    start_date = datetime.strptime(sys.argv[1], "%Y-%m-%d")
    end_date = datetime.strptime(sys.argv[2], "%Y-%m-%d")
    urls = sys.argv[3:]

    if len(urls) == 0:
        sys.exit(1)

    while True:
        available_rooms = find_available_rooms(start_date, end_date, urls)
        
        if available_rooms: 
            page_title = get_page_title(urls[0])  # Assume the title is the same for all pages for simplicity
            to = "chroion0@gmail.com"  
            subject = f"{page_title} 빈방 알림"
            body = f"{start_date.date()} ~ {end_date.date()} 까지의 빈방 목록 <br><br>"
            body += "<br>".join(available_rooms)
            send_mail(to, subject, body, urls[0])
            break  
            
        else:
            current_date = datetime.now().date()
            
            if start_date.date() <= current_date:
                page_title = get_page_title(urls[0])  # Assume the title is the same for all pages for simplicity
                to = "chroion0@gmail.com"
                subject = "빈방 검색 종료 알림"
                body = f"예약하셨던 {page_title} 사이트에서의 {start_date.date()} ~ {end_date.date()} 까지의 빈방이 없어서 검색이 종료되었기에 알려드립니다."
                send_mail(to, subject, body, urls[0], False)
                break
            time.sleep(600)


