from typing import Optional, List
from uuid import UUID

from fastapi import HTTPException, status
from sqlalchemy import select
from sqlalchemy.orm import selectinload

from src.aeros_simulation.model import AerosSimulation
from src.aeros_simulation.service import (
    get_calc_result_by,
    get_default_simulation,
    get_simulation_by_id,
    get_simulation_node_by,
)
from src.auth.service import CurrentUser
from src.database.core import DbSession
from src.database.service import search_filter_sort_paginate
from tkinter.constants import E

from src.dashboard_model.model import RBDMasterData
from src.dashboard_model.schema_masterdata import RBDMasterDataUpdate


async def _get_or_create_master_data(db_session: DbSession, name: str, default_float: float):
    query = select(RBDMasterData).where(RBDMasterData.name == name)
    result = await db_session.execute(query)
    record = result.scalars().first()
    if not record:
        record = RBDMasterData(name=name, value_float=default_float)
        db_session.add(record)
        await db_session.commit()
        await db_session.refresh(record)
    return record


async def get_master_data_list(db_session: DbSession):
    # Ensure Current EAF exists
    await _get_or_create_master_data(db_session, "Current EAF Realization", 85.62)
    await _get_or_create_master_data(db_session, "Last Overhaul Date", 0)
    query = select(RBDMasterData)
    result = await db_session.execute(query)
    return result.scalars().all()


async def update_master_data(db_session: DbSession, md_id: UUID, payload: RBDMasterDataUpdate):
    query = select(RBDMasterData).where(RBDMasterData.id == md_id)
    result = await db_session.execute(query)
    record = result.scalars().first()
    if not record:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND, detail="Master Data not found"
        )
    if payload.value_float is not None:
        record.value_float = payload.value_float
    if payload.value_string is not None:
        record.value_string = payload.value_string
    if payload.month is not None:
        record.month = payload.month
    if payload.year is not None:
        record.year = payload.year
    await db_session.commit()
    await db_session.refresh(record)
    return record


async def get_model_data(*, db_session: DbSession, simulation_id: Optional[UUID]):
    if simulation_id:
        simulation = await get_simulation_by_id(db_session=db_session, simulation_id=simulation_id)
    else:
        simulation = await get_default_simulation(db_session=db_session)

    if not simulation:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND, detail="Simulation not found"
        )


    main_calc_data = await get_calc_result_by(
        db_session=db_session, simulation_id=simulation.id, node_name="- TJB - Unit 3 -"
    )


    # Total time period
    total_time = main_calc_data.total_uptime + main_calc_data.total_downtime

    # Availability Factor (same as your first formula - this one is correct)
    availability = (main_calc_data.availability) * 100
    
    is_oh = (main_calc_data.sof >= 10) 

    # Equivalent Forced Outage Rate (EFOR)
    EFOR = main_calc_data.efor

    #Prediction
    EAF = main_calc_data.eaf
    Derating = main_calc_data.derating_hours
    Trip = main_calc_data.num_events
    EAF_KONKIN = main_calc_data.eaf_konkin
    
    SOF = main_calc_data.sof
    
    #Fetch Master Data EAF realization
    eaf_record = await _get_or_create_master_data(db_session, "Current EAF Realization", 85.62)
    eaf_real_val = eaf_record.value_float if eaf_record.value_float is not None else 85.62
    
    #Realization
    EAF_REAL = eaf_real_val
    EFOR_REAL = 1.7
    EAF_KONKIN_REAL = eaf_real_val

    powerplant_reliability = {
        "Plant Control": 98,
        "SPS": 98,
        "Turbine": 98,
        "Generator": 98,
        "Condensate Water": 98,
        "Feedwater System": 98,
        "Cooling Water": 98,
        "SCR": 98,
        "Ash Handling": 98,
        "Air Flue Gas": 98,
        "Boiler": 98,
        "SAC-IAC": 98,
        "KLH": 98,
        "CL": 98,
        "DESALINATION (CP)": 98,
        "FGD": 98,
        "CHS": 98,
        "SSB": 98,
        "WTP": 98,
    }
    
    # Fetch Forecasts
    forecast_weekly = await get_latest_sim_results_by_pattern(db_session, "Simulation_weekly_%")
    forecast_monthly = await get_latest_sim_results_by_pattern(db_session, "Simulation_monthly_%")

    return {
    "id": str(simulation.id), 
    "name": simulation.simulation_name,
    "availability": availability, 
    "EFOR": EFOR, 
    "SOF": SOF,
     "EAF": {
        "Prediction_EAF": EAF,
        "Prediction_EAF_KONKIN": EAF_KONKIN,
        "Real_EAF": EAF_REAL,
        "Real_EAF_KONKIN": EAF_KONKIN_REAL,
        "month": eaf_record.month,
        "year": eaf_record.year
    },
     "Trip": {
         "Prediction_Trip": Trip,
         "Real_Trip": Trip
     },
     "Derating": {
         "Prediction_Derating": Derating,
         "Real_Derating": Derating
     },
    "powerplant_reliability": powerplant_reliability,
    "forecast_weekly": forecast_weekly,
    "forecast_monthly": forecast_monthly
}

async def get_latest_sim_results_by_pattern(db_session: DbSession, pattern: str):
    from sqlalchemy import select
    from src.aeros_simulation.model import AerosSimulation, AerosSimulationCalcResult, AerosNode
    from src.aeros_simulation.service import get_plant_calc_result

    query = select(AerosSimulation).where(AerosSimulation.simulation_name.like(pattern)).order_by(AerosSimulation.created_at.desc()).limit(1)
    result = await db_session.execute(query)
    simulation = result.scalars().first()
    
    if not simulation:
        return None
        
    # Get plant node result
    plant_res = await get_plant_calc_result(db_session=db_session, simulation_id=simulation.id)
    
    # Get top 5 equipment causing trips (num_events)
    trip_query = select(AerosSimulationCalcResult).join(AerosNode).where(
        AerosSimulationCalcResult.aeros_simulation_id == simulation.id,
        AerosNode.node_type == 'RegularNode'
    ).options(selectinload(AerosSimulationCalcResult.aeros_node)).order_by(AerosSimulationCalcResult.num_events.desc()).limit(5)
    
    trip_res_exec = await db_session.execute(trip_query)
    trip_results = trip_res_exec.scalars().all()
    
    top_trips = []
    for tr in trip_results:
        if tr.num_events > 0:
            top_trips.append({
                "name": tr.aeros_node.node_name,
                "events": tr.num_events,
                "tag": tr.aeros_node.node_name
            })
            
    return {
        "simulation_id": str(simulation.id),
        "name": simulation.simulation_name,
        "eaf": plant_res.eaf if plant_res else 0,
        "efor": plant_res.efor if plant_res else 0,
        "trips": int(plant_res.num_events) if plant_res else 0,
        "top_trip_equipment": top_trips
    }
