import streamlit as st
import time
from datetime import datetime
from pathlib import Path
import sys
import pandas as pd

PROJECT_ROOT = Path(__file__).resolve().parents[2]
if str(PROJECT_ROOT) not in sys.path:
    sys.path.insert(0, str(PROJECT_ROOT))

from indian_paper_trading_strategy.engine.history import load_monthly_close
from indian_paper_trading_strategy.engine.market import india_market_status
from indian_paper_trading_strategy.engine.data import fetch_live_price
from indian_paper_trading_strategy.engine.strategy import allocation
from indian_paper_trading_strategy.engine.execution import try_execute_sip
from indian_paper_trading_strategy.engine.state import load_state, save_state
from indian_paper_trading_strategy.engine.db import db_connection, insert_engine_event, run_with_retry, get_default_user_id, get_active_run_id, set_context
from indian_paper_trading_strategy.engine.mtm import log_mtm, should_log_mtm

_STREAMLIT_USER_ID = get_default_user_id()
_STREAMLIT_RUN_ID = get_active_run_id(_STREAMLIT_USER_ID) if _STREAMLIT_USER_ID else None
if _STREAMLIT_USER_ID and _STREAMLIT_RUN_ID:
    set_context(_STREAMLIT_USER_ID, _STREAMLIT_RUN_ID)

def reset_runtime_state():
    def _op(cur, _conn):
        cur.execute(
            "DELETE FROM mtm_ledger WHERE user_id = %s AND run_id = %s",
            (_STREAMLIT_USER_ID, _STREAMLIT_RUN_ID),
        )
        cur.execute(
            "DELETE FROM event_ledger WHERE user_id = %s AND run_id = %s",
            (_STREAMLIT_USER_ID, _STREAMLIT_RUN_ID),
        )
        cur.execute(
            "DELETE FROM engine_state WHERE user_id = %s AND run_id = %s",
            (_STREAMLIT_USER_ID, _STREAMLIT_RUN_ID),
        )
        insert_engine_event(cur, "LIVE_RESET", data={})

    run_with_retry(_op)

def load_mtm_df():
    with db_connection() as conn:
        return pd.read_sql_query(
            "SELECT timestamp, pnl FROM mtm_ledger WHERE user_id = %s AND run_id = %s ORDER BY timestamp",
            conn,
            params=(_STREAMLIT_USER_ID, _STREAMLIT_RUN_ID),
        )

def is_engine_running():
    state = load_state(mode="LIVE")
    return state.get("total_invested", 0) > 0 or \
           state.get("nifty_units", 0) > 0 or \
           state.get("gold_units", 0) > 0

if "engine_active" not in st.session_state:
    st.session_state.engine_active = is_engine_running()

NIFTY = "NIFTYBEES.NS"
GOLD = "GOLDBEES.NS"
SMA_MONTHS = 36

def get_prices():
    try:
        nifty = fetch_live_price(NIFTY)
        gold = fetch_live_price(GOLD)
        return nifty, gold
    except Exception as e:
        st.error(e)
        return None, None

SIP_AMOUNT = st.number_input("SIP Amount (\u20B9)", 500, 100000, 5000)
SIP_INTERVAL_SEC = st.number_input("SIP Interval (sec) [TEST]", 30, 3600, 120)
REFRESH_SEC = st.slider("Refresh interval (sec)", 5, 60, 10)

st.title("SIPXAR INDIA - Phase-1 Safe Engine")

market_open, market_time = india_market_status()
st.info(f"NSE Market {'OPEN' if market_open else 'CLOSED'} | IST {market_time}")
if not market_open:
    st.info("Market is closed. Portfolio values are frozen at last available prices.")

col1, col2 = st.columns(2)

with col1:
    if st.button("START ENGINE"):
        if is_engine_running():
            st.info("Engine already running. Resuming.")
            st.session_state.engine_active = True
        else:
            st.session_state.engine_active = True

            # HARD RESET ONLY ON FIRST START
            reset_runtime_state()

            save_state({
                "total_invested": 0.0,
                "nifty_units": 0.0,
                "gold_units": 0.0,
                "last_sip_ts": None,
            }, mode="LIVE", emit_event=True, event_meta={"source": "streamlit_start"})

            st.success("Engine started")

with col2:
    if st.button("KILL ENGINE"):
        st.session_state.engine_active = False

        reset_runtime_state()

        st.warning("Engine killed and state wiped")
        st.stop()

if not st.session_state.engine_active:
    st.stop()

state = load_state(mode="LIVE")
nifty_price, gold_price = get_prices()

if nifty_price is None:
    st.stop()

st.subheader("Latest Market Prices (LTP)")

c1, c2 = st.columns(2)

with c1:
    st.metric(
        label="NIFTYBEES",
        value=f"\u20B9{nifty_price:,.2f}",
        help="Last traded price (delayed)"
    )

with c2:
    st.metric(
        label="GOLDBEES",
        value=f"\u20B9{gold_price:,.2f}",
        help="Last traded price (delayed)"
    )

st.caption(f"Price timestamp: {datetime.now().strftime('%H:%M:%S')}")

nifty_hist = load_monthly_close(NIFTY)
gold_hist = load_monthly_close(GOLD)

nifty_sma = nifty_hist.rolling(SMA_MONTHS).mean().iloc[-1]
gold_sma = gold_hist.rolling(SMA_MONTHS).mean().iloc[-1]

eq_w, gd_w = allocation(
    sp_price=nifty_price,
    gd_price=gold_price,
    sp_sma=nifty_sma,
    gd_sma=gold_sma
)

state, executed = try_execute_sip(
    now=datetime.now(),
    market_open=market_open,
    sip_interval=SIP_INTERVAL_SEC,
    sip_amount=SIP_AMOUNT,
    sp_price=nifty_price,
    gd_price=gold_price,
    eq_w=eq_w,
    gd_w=gd_w,
    mode="LIVE",
)

now = datetime.now()

if market_open and should_log_mtm(None, now):
    portfolio_value, pnl = log_mtm(
        nifty_units=state["nifty_units"],
        gold_units=state["gold_units"],
        nifty_price=nifty_price,
        gold_price=gold_price,
        total_invested=state["total_invested"],
    )
else:
    # Market closed -> freeze valuation (do NOT log)
    portfolio_value = (
        state["nifty_units"] * nifty_price +
        state["gold_units"] * gold_price
    )
    pnl = portfolio_value - state["total_invested"]

st.subheader("Equity Curve (Unrealized PnL)")

mtm_df = load_mtm_df()

if "timestamp" in mtm_df.columns and "pnl" in mtm_df.columns and len(mtm_df) > 1:
    mtm_df["timestamp"] = pd.to_datetime(mtm_df["timestamp"])
    mtm_df = mtm_df.sort_values("timestamp").set_index("timestamp")

    st.line_chart(mtm_df["pnl"], height=350)
else:
    st.warning("Not enough MTM data or missing columns. Expected: timestamp, pnl.")

st.metric("Total Invested", f"\u20B9{state['total_invested']:,.0f}")
st.metric("NIFTY Units", round(state["nifty_units"], 4))
st.metric("Gold Units", round(state["gold_units"], 4))
st.metric("Portfolio Value", f"\u20B9{portfolio_value:,.0f}")
st.metric("PnL", f"\u20B9{pnl:,.0f}")

time.sleep(REFRESH_SEC)
st.rerun()

