import io
import numpy as np
import pandas as pd
import plotly.express as px
import streamlit as st
st.set_page_config(page_title='AIMPACT | Schedule Risk',page_icon='📅',layout='wide')
st.title('📅 Smart Schedule Delay Explorer')
st.caption('Transparent RULE-BASED screening demo, not an ML delay prediction model. No schedule changes are made.')
@st.cache_data
def example():
 return pd.DataFrame([
  ['Excavation',12,4,0,1,1,2],['PCC',6,2,2,0,0,0],['Raft rebar',18,10,7,4,1,5],
  ['Raft concrete',4,1,0,3,0,2],['Shell lift 01',7,0,1,1,3,0],['Shell lift 02',7,0,4,3,5,1],
  ['Platform steel',14,2,3,7,1,3],['Flue can erection',20,4,8,10,2,6]],
  columns=['activity','planned_days','progress_pct','drawing_lag_days','material_lag_days','weather_days','predecessor_lag_days'])
upload=st.file_uploader('Upload activity-level CSV or Excel (or use sample data)',type=['csv','xlsx'])
try:
 df=(pd.read_csv(upload) if upload.name.lower().endswith('.csv') else pd.read_excel(upload)) if upload else example()
 required=['activity','planned_days','progress_pct','drawing_lag_days','material_lag_days','weather_days','predecessor_lag_days']
 missing=[c for c in required if c not in df.columns]
 if missing: st.error('Missing columns: '+', '.join(missing));st.stop()
 df=df[required].copy();df['activity']=df['activity'].astype(str)
 for col in required[1:]: df[col]=pd.to_numeric(df[col],errors='coerce').fillna(0).clip(lower=0)
 if (df['progress_pct']>100).any():st.error('Progress must be 0–100%.');st.stop()
except Exception as exc:st.error(f'Invalid file: {exc}');st.stop()
with st.sidebar:
 st.header('Editable screening weights')
 weights={x:st.slider(x,0.0,2.0,v,.1) for x,v in [('drawing_lag_days',.8),('material_lag_days',1.0),('weather_days',.4),('predecessor_lag_days',.9)]}
 threshold=st.slider('High-risk threshold (days)',1,30,8)
df['risk_score_days']=sum(df[k]*w for k,w in weights.items())
df['risk_class']=np.where(df.risk_score_days>=threshold,'High',np.where(df.risk_score_days>=threshold/2,'Medium','Low'))
a,b,c=st.columns(3);a.metric('Activities',len(df));b.metric('High-risk activities',int((df.risk_class=='High').sum()));c.metric('Average screening score',f'{df.risk_score_days.mean():.1f} days')
st.plotly_chart(px.bar(df.sort_values('risk_score_days'),x='risk_score_days',y='activity',color='risk_class',orientation='h',title='Indicative constraint burden'),use_container_width=True)
st.dataframe(df,use_container_width=True)
st.download_button('Download annotated CSV',df.to_csv(index=False).encode(),'screened_schedule.csv','text/csv')
st.info('Risk scores are weighted constraint indicators, not forecast completion dates. Avoid using for contractual decisions without validation.')
