"""Streamlit front end: streamlit run app.py"""
import pandas as pd
import streamlit as st

import doctor
from doctor.jscompat import js_str, to_fixed

NO_TARGET = "(none)"
AUTO_TARGET = "(guess from column names)"


st.set_page_config(
    page_title="Dataset Doctor",
    page_icon="🩺",
    layout="wide",
)

st.title("🩺 Dataset Doctor")

st.write(
    "Upload a CSV and I'll check it for the data problems that quietly ruin a model: "
    "leaks, duplicates, disguised missing values, mixed formats, train/test overlap and more."
)


@st.cache_data(show_spinner=False)
def load(data: bytes):
    return doctor.parse_csv(data.decode("utf-8", errors="replace"))


@st.cache_data(show_spinner="Examining the data...")
def run(train_bytes: bytes, target_choice: str, test_bytes, today: str):
    table = load(train_bytes)
    test = load(test_bytes) if test_bytes else None
    if target_choice == AUTO_TARGET:
        target = doctor.AUTO
    elif target_choice == NO_TARGET:
        target = None
    else:
        target = target_choice
    return doctor.analyze(table, target=target, compare=test, today=today or None)


uploaded_file = st.file_uploader("Upload a CSV file", type=["csv", "tsv", "txt"])
test_file = st.file_uploader("Optional: the matching test file, to check train vs test", type=["csv", "tsv", "txt"])

if uploaded_file is not None:
    raw = uploaded_file.getvalue()
    table = load(raw)
    if not table.columns:
        st.error("That file looks empty.")
        st.stop()

    c1, c2 = st.columns([2, 1])
    target_choice = c1.selectbox("Target column (what a model would predict)",
                                 [AUTO_TARGET, NO_TARGET] + list(table.columns))
    today = c2.text_input("Today (YYYY-MM-DD, for the future-dates check)",
                          value=pd.Timestamp.today().strftime("%Y-%m-%d"))

    report = run(raw, target_choice, test_file.getvalue() if test_file is not None else None, today)
    score = report["score"]
    issues = report["issues"]

    st.subheader("Dataset Overview")

    col1, col2, col3, col4 = st.columns(4)
    col1.metric("Health Score", f"{score['overall']}/100")
    col2.metric("Rows", report["rows"])
    col3.metric("Columns", len(report["columns"]))
    t = report["target"]
    col4.metric("Target", f"{t['column']} ({t.get('kind')})" if t else "none")

    pen = [(c, score["penalties"].get(c, 0)) for c in score["order"]]
    st.caption("Penalty by category: " + " · ".join(f"{c} −{js_str(round(p, 1))}" for c, p in pen))

    st.subheader("Issues")

    if not issues:
        st.success("No major issues detected.")

    icons = {"high": "🔴", "medium": "🟠", "low": "🔵", "info": "⚪"}
    for issue in issues:
        label = f"{icons[issue['severity']]} [{issue['severity'].upper()}] {issue['title']}  ·  {issue['category']} −{js_str(issue['penalty'])}"
        with st.expander(label):
            st.write(issue["detail"])
            ev = issue.get("evidence") or {}
            if ev.get("values"):
                st.markdown("**Evidence:** " + "; ".join(f"`{v}`" for v in ev["values"]))
            if ev.get("rows"):
                st.markdown("**Rows (file line numbers):** " + ", ".join(str(r) for r in ev["rows"]))
            st.code(issue["fix"], language="python")

    st.subheader("Columns")
    st.dataframe(pd.DataFrame([{
        "column": c["name"], "type": c["type"], "missing": c["missing"],
        "missing %": round(100 * c["missingFrac"], 1), "unique": c["unique"],
        "top values": ", ".join(f"{v} ({k})" for v, k in c["top"][:3]),
        "issues": len(c["issues"]),
    } for c in report["columns"]]), hide_index=True)

    if report["featureStrength"]:
        metric = report["featureStrength"][0]["metric"]
        st.subheader(f"Single-feature strength ({metric}, out-of-fold)")
        st.caption("How well each column predicts the target on its own. A column far ahead of the rest is usually a leak.")
        fs = pd.DataFrame([{"column": s["column"], metric: s["score"]} for s in report["featureStrength"]])
        st.bar_chart(fs, x="column", y=metric, horizontal=True, sort=False)

    st.subheader("Fix it")
    name = uploaded_file.name
    base = name[:-4] if name.lower().endswith(".csv") else name
    cleaned = doctor.apply_fixes(table, report)
    d1, d2, d3 = st.columns(3)
    d1.download_button("Cleaned CSV", doctor.to_csv(cleaned).encode("utf-8"), file_name=base + "_clean.csv", mime="text/csv")
    d2.download_button("Cleaning script (pandas)", doctor.cleaning_script(report, filename=name), file_name="clean_" + base + ".py", mime="text/x-python")
    d3.download_button("Report (Markdown)", doctor.report_markdown(report, filename=name), file_name=base + "_report.md", mime="text/markdown")
    if cleaned.log:
        st.caption("The cleaned CSV: " + "; ".join(cleaned.log))

    st.subheader("Preview")

    st.dataframe(pd.DataFrame(table.rows[:20], columns=table.columns))
