import math
import yaml
import numpy as np
from datetime import date

KWH_PRICE = 0.45
KWH_PRICE_HOME = 0.1745
GAS_PRICE = 3.25
GAL_TO_KWH = 33.7
BATTERY_USAGE_EV = 0.7
GAS_STOP_MINUTES = 15.0
GAS_STOP_HOURS = GAS_STOP_MINUTES / 60.0
EV_DWELL_TIME_MINUTES = 5.0

def labelQuartiles(data, key, reversed=False):
    values = []
    for car in data:
        values.append(car[key])
    q1 = np.percentile(values, 25)
    q2 = np.percentile(values, 50)
    q3 = np.percentile(values, 75)
    reverseMap = {"Q1": "Q4", "Q2": "Q3", "Q3": "Q2", "Q4": "Q1"}
    for car in data:
        value = car[key]
        if value <= q1:
            quartile = 'Q1'
        elif value <= q2:
            quartile = 'Q2'
        elif value <= q3:
            quartile = 'Q3'
        else:
            quartile = 'Q4'
        if reversed:
            quartile = reverseMap[quartile]
        car[key] = {"value": value, "quartile": quartile}

# def labelQuartiles(data, key, reversed=False):
#     values = []
#     for car in data:
#         values.append(car[key])
#     values.sort(reverse=not reversed)

#     for car in data:
#         value = car[key]
#         quartile = values.index(value) / len(values)
#         quartile *= 100
#         quartile = int(quartile)
#         quartile = f"P{quartile}"
#         car[key] = {"value": value, "quartile": quartile}

def fill_template(data):
    with open("table data.html") as f:
        table_data = f.read()
    with open("index template.html") as f:
        index_template = f.read()
    filled_template = index_template.replace("{table}", table_data)
    today = date.today()
    today = today.strftime("%B %d, %Y")
    filled_template = filled_template.replace("{car list date}", today)
    with open("index.html", 'w') as f:
        f.write(filled_template)

def load_data():
    with open("cars.yaml", "r") as file:
        data = yaml.safe_load(file)
    return data

def calculate_car(car, fuel, stats):
    print(f"Calculating car: {car}")
    
    tank_size = stats['epa range'] / stats['epa combined mpg']
    mpg_highway = stats['epa highway mpg']
    highway_range = tank_size * mpg_highway
    mi_kwh = mpg_highway / GAL_TO_KWH
    
    if fuel == "gas":
        dollars_per_100_mi = (100.0 / mpg_highway) * GAS_PRICE
        stop_time = GAS_STOP_HOURS

    if fuel == "electric":
        dollars_per_100_mi = (100.0 / mi_kwh) * KWH_PRICE
        stop_time = stats['10% to 80% charge time'] / 60

    range_optimal = highway_range * BATTERY_USAGE_EV
    drive_time = range_optimal / 75.0
    trip_charging_percent = (stop_time / (drive_time + stop_time))

    roadtrip_time = 1000 / 70
    roadtrip_time += roadtrip_time * trip_charging_percent
    roadtrip_stops = math.ceil((1000 - highway_range) / range_optimal)

    return {
        "car": car,
        "fuel type": fuel,
        "hands free": stats['hands free highway'],
        "trip charging percent": trip_charging_percent,
        "dollars per 100 miles": dollars_per_100_mi,
        "highway mi/kwh": mi_kwh,
        "highway range 100% to 0%": highway_range,
        "highway range 80% to 10%": range_optimal,
        "interior volume": stats['interor volume'],
        "stop time": stop_time * 60,
        "1000 mile roadtrip time": roadtrip_time,
        "1000 mile roadtrip stops": roadtrip_stops,
    }

def calculate_evs(data):
    car_list = []
    for car, stats in data['EVs'].items():
        car_list.append(calculate_car(car, "electric", stats))
    return car_list

def calculate_gas(data):
    car_list = []
    for car, stats in data['gas'].items():
        car_list.append(calculate_car(car, "gas", stats))
    return car_list

def formatCarName(car, key):
    if car['fuel type'] == "gas":
        return car['fuel type'], f"{car[key]} (gas)"
    else:
        return car['fuel type'], car[key]

def formatTripPercent(car, key):
    return car[key]['quartile'], f"{car[key]['value'] * 100:.1f}%"

def formatDollars(car, key):
    return car[key]['quartile'], f"${car[key]['value']:,.2f}"

def format_mi_kwh(car, key):
    return car[key]['quartile'], f"{car[key]['value']:,.2f} mi/kWh"

def format_int(car, key):
    return car[key]['quartile'], f"{car[key]['value']:.0f}"

def format_min(car, key):
    return car[key]['quartile'], f"{car[key]['value']:.0f} min"

def format_hands_free(car, key):
    if car["hands free"]:
        return "Q1", "Yes"
    else:
        return "Q3", "No"

def format_miles(car, key):
    return car[key]['quartile'], f"{car[key]['value']:.0f} mi"

def format_volume(car, key):
    return car[key]['quartile'], f"{car[key]['value']:.0f} cu ft"

def format_roadtrip_time(car, key):
    roadtrip_time = car[key]['value']
    roadtrip_hours = math.floor(roadtrip_time)
    roadtrip_minutes = math.floor((roadtrip_time - roadtrip_hours) * 60)
    roadtrip_time_string = f"{roadtrip_hours}h {roadtrip_minutes}m"
    return car[key]['quartile'], roadtrip_time_string

def save_data(car_list):
    printFields = [
        {"header": "Car", "key": "car", "formatter": formatCarName},
        {"header": "Percent of trip charging", "key": "trip charging percent", "formatter": formatTripPercent},
        {"header": "1000 mile roadtrip time", "key": "1000 mile roadtrip time", "formatter": format_roadtrip_time},
        {"header": "1000 mile roadtrip stops", "key": "1000 mile roadtrip stops", "formatter": format_int},
        {"header": "Stop time 10% to 80% charge", "key": "stop time", "formatter": format_min},
        {"header": "estimated 80% to 10% highway range", "key": "highway range 80% to 10%", "formatter": format_miles},
        {"header": "estimated 100% to 0% highway range", "key": "highway range 100% to 0%", "formatter": format_miles},
        {"header": "interior volume", "key": "interior volume", "formatter": format_volume},
        {"header": "$/100mi public charging", "key": "dollars per 100 miles", "formatter": formatDollars},
        {"header": "EPA mi/kwh highway", "key": "highway mi/kwh", "formatter": format_mi_kwh},
        {"header": "Hands free upgrade/trim available?", "key": "hands free", "formatter": format_hands_free},
    ]

    with open("table data.html", 'w') as f:
        f.write("<table id=\"myTable\" class=\"display\">\n")
        f.write("<thead>\n")
        f.write("<tr>\n")
        for field in printFields:
            f.write(f"<th>{field['header']}</th>\n")
        f.write("</tr>\n")
        f.write("</thead>\n")
        f.write("<tbody>\n")
        for car in car_list:
            print(f"Writing row for {car['car']}")
            f.write("<tr>\n")
            for field in printFields:
                print(f"Writing field {field}")
                html_class, content = field["formatter"](car, field["key"])
                f.write(f"<td class=\"{html_class}\">{content}</td>\n")
            f.write("</tr>\n")
        f.write("</tbody>\n")
        f.write("</table>\n")

def main():
    data = load_data()

    car_list = calculate_evs(data) + calculate_gas(data)
    car_list.sort(key=lambda d: d["trip charging percent"])

    labelQuartiles(car_list, "trip charging percent")
    labelQuartiles(car_list, "dollars per 100 miles")
    labelQuartiles(car_list, "highway mi/kwh", reversed=True)
    labelQuartiles(car_list, "highway range 100% to 0%", reversed=True)
    labelQuartiles(car_list, "interior volume", reversed=True)
    labelQuartiles(car_list, "stop time")
    labelQuartiles(car_list, "highway range 80% to 10%", reversed=True)
    labelQuartiles(car_list, "1000 mile roadtrip time")
    labelQuartiles(car_list, "1000 mile roadtrip stops")

    save_data(car_list)
    fill_template(data)

if __name__ == "__main__":
    main()