import os
import pymysql
from http.server import HTTPServer, BaseHTTPRequestHandler
import json
import pandas as pd

UPLOAD_DIR = "uploads"
DB_CONFIG = {
    "host": "localhost",
    "user": "root",
    "password": "",
    "database": "optimization",
}

class SimpleHandler(BaseHTTPRequestHandler):
    def _set_headers(self, content_type="text/html"):
        self.send_response(200)
        self.send_header("Content-type", content_type)
        self.end_headers()

    def do_GET(self):
        if self.path == "/":
            self._set_headers()
            with open("upload.html", "rb") as f:
                self.wfile.write(f.read())
        elif self.path == "/results":
            self._set_headers()
            with open("results.html", "rb") as f:
                self.wfile.write(f.read())
        elif self.path == "/script.js":
            self._set_headers("application/javascript")
            with open("script.js", "rb") as f:
                self.wfile.write(f.read())
        elif self.path.startswith("/downloads/"):
            file_path = self.path.lstrip("/")
            
            if os.path.exists(file_path):
                self._set_headers("application/octet-stream")
                with open(file_path, "rb") as f:
                    self.wfile.write(f.read())
            else:
                self.send_error(404, "File Not Found")
        else:
            self.send_error(404)

    def do_POST(self):
        if self.path == "/upload":
            content_type = self.headers['Content-Type']
            if "multipart/form-data" in content_type:
                boundary        = content_type.split("boundary=")[1].encode()
                content_length  = int(self.headers['Content-Length'])
                body            = self.rfile.read(content_length)

                # Split form parts
                parts           = body.split(b"--" + boundary)
                for part in parts:
                    if b"Content-Disposition" in part and b"filename=" in part:
                        header, file_data   = part.split(b"\r\n\r\n", 1)
                        file_data           = file_data.rsplit(b"\r\n", 1)[0]

                        filename_line   = header.decode(errors='ignore')
                        filename        = filename_line.split("filename=")[1].split("\r\n")[0].strip('"')
                        filepath        = os.path.join(UPLOAD_DIR, filename)

                        with open(filepath, "wb") as f:
                            f.write(file_data)

                        self.save_to_mysql(filepath)

                self.send_response(302)
                self.send_header("Location", "/results")
                self.end_headers()

        elif self.path == "/compute":
            content_length  = int(self.headers.get('Content-Length', 0))
            post_data       = self.rfile.read(content_length)
            try:
                data            = json.loads(post_data.decode('utf-8'))
                h2_storage      = float(data.get("h2_storage", 0))
                bess_storage    = float(data.get("bess_storage", 0))
                solar_energy    = float(data.get("solar_energy", 0))
                wind_energy     = float(data.get("wind_energy", 0))
                electrolyzer    = float(data.get("electrolyzer", 0))
            except Exception as e:
                self.send_response(400)
                self._set_headers("application/json")
                self.wfile.write(json.dumps({"error": "Invalid JSON input", "details": str(e)}).encode('utf-8'))
                return

            print(f"Received data: h2_storage={h2_storage}, bess_storage={bess_storage}, solar_energy={solar_energy}, wind_energy={wind_energy}, electrolyzer={electrolyzer}")
            # Now call your DB logic with these values
            result = self.compute_from_db(h2_storage, bess_storage, solar_energy, wind_energy, electrolyzer)

            self._set_headers("application/json")
            self.wfile.write(json.dumps(result).encode('utf-8'))

    def save_to_mysql(self, filepath):
        conn = pymysql.connect(**DB_CONFIG)
        cursor = conn.cursor()
        # cursor.execute("CREATE TABLE IF NOT EXISTS data (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255), value INT)")
        cursor.execute("TRUNCATE `csv_data`")
        with open(filepath, "r") as f:
            next(f)
            row_index = 0
            for line in f:
                if row_index == -1:
                    row_index += 1
                    continue
                try:
                    solar_enery, wind_energy = line.strip().split(',')
                    cursor.execute("INSERT INTO csv_data (row_index, solar_energy, wind_energy) VALUES (%s, %s, %s)", (row_index, float(solar_enery), float(wind_energy)))
                    row_index += 1
                except:
                    continue
        conn.commit()
        cursor.close()
        conn.close()

    def compute_from_db(self, h2_storage, bess_storage, solar_energy, wind_energy, electrolyzer):
        print(f"Solar Energy: {solar_energy}, Wind Energy: {wind_energy}, Electrolyzer: {electrolyzer}, BESS Storage: {bess_storage}, H2 Storage: {h2_storage}")

        conn    = pymysql.connect(**DB_CONFIG)
        cursor  = conn.cursor(pymysql.cursors.DictCursor)
        cursor.execute("SELECT solar_energy AS Solar, wind_energy AS Wind FROM csv_data ORDER BY row_index")
        result  = cursor.fetchall()
        cursor.close()
        conn.close()

        df = pd.DataFrame(result)
        
        # -----------------------------
        # Configurable Inputs
        # -----------------------------
        nh3_annual_target_tons  = 200000  # Target NH3 production per year (tons)

        # Installed capacities
        solar_capacity_mw               = solar_energy  # MW
        wind_capacity_mw                = wind_energy   # MW
        electrolyser_capacity_mw        = electrolyzer  # MW
        bess_capacity_mwh               = bess_storage  # MWh
        h2_storage_capacity_tons        = h2_storage  # Max H2 tank storage (tons)
        nh3_plant_hourly_capacity_tons  = 28.75  # NH3 output capacity per hour
        nh3_min_utilization             = 0.2  # 20% min capacity

        # Constants
        battery_efficiency          = 0.90
        transmission_loss_pct       = 0.045
        power_to_nh3_MW             = 20  # NH3 needs 20 MW/hour
        grid_energy_limit_kwh_year  = 50000  # 50 MWh/year
        kwh_per_kg_h2               = 55
        kg_h2_per_ton_nh3           = 178

        # -----------------------------
        # Initialization
        # -----------------------------
        battery_energy      = 0
        h2_storage          = 0
        grid_energy_used    = 0
        nh3_produced_total  = 0

        total_h2_produced   = 0
        total_energy_wasted = 0

        hourly_stats = []

        for idx, row in df.iterrows():
            print(f"Hour {idx + 1}")
            solar_gen           = max(0, row['Solar']) * solar_capacity_mw/1000
            wind_gen            = max(0, row['Wind']) * wind_capacity_mw/1000
            print(f"Solar Gen: {solar_gen:.2f} MWh, Wind Gen: {wind_gen:.2f} MWh")

            total_genrated      = solar_gen + wind_gen
            transmission_loss   = total_genrated * transmission_loss_pct
            total_gen           = total_genrated - transmission_loss

            bess_start          = battery_energy
            bess_store          = 0
            bess_discharge      = 0
            energy_dispatch     = 0
            energy_loss         = transmission_loss
            energy_delivered    = total_gen
            ei_utilization      = 0
            h2_start            = h2_storage
            grid_needed         = 0
            h2_storage_used     = 0
            h2_storage_stored   = 0

            # Step 1: Power NH3 plant (20 MW fixed demand)
            power_for_nh3   = min(power_to_nh3_MW, total_gen)
            if power_for_nh3 < power_to_nh3_MW:
                grid_needed = power_to_nh3_MW - power_for_nh3
                # Check if we can use grid energy
                if (grid_energy_used + grid_needed) <= (grid_energy_limit_kwh_year / 1000):
                    power_for_nh3       += grid_needed
                    grid_energy_used    += grid_needed
                else:
                    # Use grid energy only if we have not reached the limit
                    grid_needed = max(0, (grid_energy_limit_kwh_year / 1000) - grid_energy_used)
                    power_for_nh3       += grid_needed
                    grid_energy_used    += grid_needed

            remaining_power = total_gen - (power_for_nh3 if power_for_nh3 <= total_gen else total_gen)

            # Step 2: Run Electrolyser
            power_for_electrolyser  = min(electrolyser_capacity_mw, remaining_power)
            h2_produced_kg          = power_for_electrolyser * 1000 / kwh_per_kg_h2
            h2_storage              += h2_produced_kg / 1000  # in tons
            total_h2_produced       += h2_storage

            remaining_power         -= power_for_electrolyser

            energy_dispatch         = power_for_nh3 + power_for_electrolyser

            # Step 3: Excess power → Battery
            if remaining_power > 0:
                storable_energy = min(bess_capacity_mwh - battery_energy, remaining_power)
                battery_energy  += storable_energy * battery_efficiency
                remaining_power -= storable_energy
                bess_store      = storable_energy

            total_energy_wasted += remaining_power

            # Step 4: NH3 production from H2
            max_h2_available    = h2_storage * 1000
            max_nh3_possible    = max_h2_available / kg_h2_per_ton_nh3
            max_nh3_possible    = min(max_nh3_possible, nh3_plant_hourly_capacity_tons)

            if max_nh3_possible >= (nh3_plant_hourly_capacity_tons * nh3_min_utilization):
                nh3_produced = max_nh3_possible
            else:
                nh3_produced = 0

            h2_consumed = nh3_produced * kg_h2_per_ton_nh3
            h2_storage  -= h2_consumed / 1000
            nh3_produced_total += nh3_produced

            # Calculate H2 used from storage
            if h2_produced_kg < h2_consumed:
                if h2_storage > 0:
                    h2_storage_used = h2_consumed - h2_produced_kg
                    if h2_storage_used < 0:
                        h2_storage_used = 0

            # Step 5: Draw battery when needed
            if power_for_nh3 < power_to_nh3_MW:
                deficit = power_to_nh3_MW - power_for_nh3
                if battery_energy >= deficit:
                    battery_energy -= deficit
                    power_for_nh3 += deficit
                    bess_discharge = deficit

            h2_storage_e1 = h2_storage

            # Step 6: Limit H2 storage
            if h2_storage > h2_storage_capacity_tons:
                h2_storage = h2_storage_capacity_tons

            h2_storage_stored = h2_storage - h2_start

            # Step 7: Calculate energy utilization
            if power_for_electrolyser > 0:
                ei_utilization = ((h2_produced_kg/1000)*kwh_per_kg_h2 / power_for_electrolyser)*100
            else:
                ei_utilization = 0

            # Save stats
            hourly_stats.append({
                'hour'                  : idx,
                'solar_gen'             : solar_gen,
                'wind_gen'              : wind_gen,
                'total_gen'             : total_genrated,
                'bess_start'            : bess_start,
                'bess_store'            : bess_store,
                'bess_discharge'        : bess_discharge,
                'bess_end'              : battery_energy,
                'energy_dispatch'       : energy_dispatch,
                'energy_loss'           : energy_loss,
                'energy_delivered'      : power_for_nh3 + power_for_electrolyser,
                'power_nh3_s'           : power_for_nh3,
                'power_electrolyser_t'  : power_for_electrolyser,
                'h2_produced_kg'        : h2_produced_kg/1000,
                'ei_utilization'        : ei_utilization,
                'h2_storage_tons'       : h2_storage,
                'h2_direct_to_nh3'      : h2_consumed/1000,
                'nh3_produced_tons'     : nh3_produced,
                'nh3_utilization'       : nh3_produced / nh3_plant_hourly_capacity_tons * 100,
                'h2_storage_start'      : h2_start,
                'h2_storage_used'       : h2_storage_used,
                'h2_storage_stored'     : h2_storage_stored,
                'h2_storage_e1'         : h2_storage_e1,
                'h2_storage_end'        : h2_storage,
                'grid_energy_used_mwh'  : grid_needed,
                'totao_grid_energy_used': grid_energy_used,
            })
            
            # if idx > 0:
            #     print(hourly_stats[-10:])
            #     break

        # print(hourly_stats[-1])
        # -----------------------------
        # Final Report
        # -----------------------------
        df_stats = pd.DataFrame(hourly_stats)
        print(f"\n✅ Total NH3 produced: {nh3_produced_total:.2f} tons")
        print(f"✅ Grid energy used: {grid_energy_used:.2f} MWh")
        print(f"✅ Final H2 storage: {h2_storage:.2f} tons")
        print(f"✅ Final Battery storage: {battery_energy:.2f} MWh")
        print(f"✅ Total H2 Produced: {total_h2_produced:.2f} MWh")
        print(f"✅ Total Energy Wasted: {total_energy_wasted:.2f} MWh")

        dataTable = f"""
        <thead class="thead-dark">
            <tr><th colspan="2" class="text-center">Simulation Results</th></tr>
        </thead>
        <tbody>
            <tr><td>Total NH3 Produced:</td> <td>{nh3_produced_total:.2f} Tons</td></tr>
            <tr><td>Grid Energy Used:</td> <td>{grid_energy_used:.2f} MWh</td></tr>
            <tr><td>Final H2 Storage:</td> <td>{h2_storage:.2f} Tons</td></tr>
            <tr><td>Final Battery Storage:</td> <td>{battery_energy:.2f} MWh</td></tr>
            <tr><td>Total H2 Produced:</td> <td>{total_h2_produced:.2f} MWh</td></tr>
            <tr><td>Total Energy Wasted:</td> <td>{total_energy_wasted:.2f} MWh</td></tr>
        </tbody>
        """

        filename = "downloads/NH3-Simulation.csv"
        if os.path.exists(filename):
            os.remove(filename)

        df_stats.to_csv(filename, index=False)
        

        plant_capital_cost  = (1 * 250000 * 1 * 1 * 1.4) / 1000
        h2_storage_cost     = (h2_storage_capacity_tons * 500 * 1.2 * 1 * 1.4) / 1000
        bess_cost           = (bess_capacity_mwh * 100 * 1.1 * 1.05 * 1.4) / 1000
        soler_energy_cost   = (solar_capacity_mw * 400 * 1.00 * 1.11 * 1.40) / 1000
        wind_energy_cost    = (wind_capacity_mw * 800 * 1.00 * 1.125 * 1.40) / 1000
        electrolyzer_cost   = (electrolyser_capacity_mw * 350 * 1.20 * 1.125 * 1.40) / 1000
        total_cost          = (plant_capital_cost + h2_storage_cost + bess_cost + soler_energy_cost + wind_energy_cost + electrolyzer_cost)

        costTable = f"""
        <thead class="thead-dark">
            <tr><th colspan="2" class="text-center">Capital Data</th></tr>
        </thead>
        <tbody>
            <tr><td>Plant Capital Cost:</td> <td> {plant_capital_cost:.2f}</td></tr>
            <tr><td>H2 Storage Cost:</td> <td> {h2_storage_cost:.2f}</td></tr>
            <tr><td>BESS Cost:</td> <td> {bess_cost:.2f}</td></tr>
            <tr><td>Solar Energy Cost:</td> <td> {soler_energy_cost:.2f}</td></tr>
            <tr><td>Wind Energy Cost:</td> <td> {wind_energy_cost:.2f}</td></tr>
            <tr><td>Electrolyzer Cost:</td> <td> {electrolyzer_cost:.2f}</td></tr>
            <tr><td>Total Cost:</td> <td> {total_cost:.2f}</td></tr>
        </tbody>
        """
        
        response = {
            "dataTable": dataTable,
            "costTable": costTable
        }
        
        return response

def run():
    os.makedirs(UPLOAD_DIR, exist_ok=True)
    server_address = ('', 8000)
    httpd = HTTPServer(server_address, SimpleHandler)
    print("Server running at http://localhost:8000")
    httpd.serve_forever()

if __name__ == "__main__":
    run()