#!/usr/bin/env python3
"""Regression test for the dashboard KPI repoint + lp_profiles retirement (2026-06-16).

"Total Committed" used to SUM lp_profiles.commitment_amount — an orphaned table with no
reachable input path, so the dashboard read ~$0 while the real commitments lived in the
fundraising grid. It now sums fundraising_investors.total_invested (the canonical grid
rollup) with graveyarded (written-off) investors excluded, "Total Funded" is dropped
(the grid has no funded-vs-committed concept), and the /api/lp-profiles* + lp-breakdown
endpoints are gone.

This boots the REAL server against a temp DB, seeds two grid investors (one live, one
graveyarded), and asserts: total_committed reflects the live grid rollup only, the
metrics no longer carry a total_funded key, and the retired routes 404. Synthetic only.

Run: cd backend && python3 test_dashboard_report.py
"""
import http.client
import json
import os
import sqlite3
import sys
import tempfile
import threading
from http.server import ThreadingHTTPServer

_DATA = tempfile.mkdtemp()
os.environ["CRM_DATA_DIR"] = _DATA
os.environ["CRM_DB_PATH"] = os.path.join(_DATA, "crm.db")

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import server  # noqa: E402

FAILS = []


def check(cond, msg):
    print(("  PASS " if cond else "  FAIL ") + msg)
    if not cond:
        FAILS.append(msg)


class _Quiet(server.CRMHandler):
    def log_message(self, *a):
        pass


def _get(port, path, token):
    conn = http.client.HTTPConnection("127.0.0.1", port, timeout=10)
    conn.request("GET", path, headers={"Authorization": "Bearer " + token})
    resp = conn.getresponse()
    body = resp.read().decode("utf-8", "replace")
    conn.close()
    data = None
    if body:
        try:
            data = json.loads(body)
        except ValueError:
            pass
    return resp.status, data


def seed():
    c = sqlite3.connect(os.environ["CRM_DB_PATH"])
    c.execute("INSERT INTO users (id,username,email,password_hash,full_name,role,is_active) "
              "VALUES ('u1','grant','grant@ten31.example','x','Grant','admin',1)")
    # live investor committed 3,000,000; graveyarded investor committed 500,000 (must be excluded)
    c.execute("INSERT INTO fundraising_investors (id,investor_name,source_row_id,total_invested,graveyard) "
              "VALUES ('fiLive','Harbor LP','rowLive',3000000,0)")
    c.execute("INSERT INTO fundraising_investors (id,investor_name,source_row_id,total_invested,graveyard) "
              "VALUES ('fiDead','Passed LP','rowDead',500000,1)")
    c.commit()
    c.close()


def main():
    server.init_db()
    seed()
    token = server.create_token("u1", "grant", "admin")

    httpd = ThreadingHTTPServer(("127.0.0.1", 0), _Quiet)
    port = httpd.server_address[1]
    threading.Thread(target=httpd.serve_forever, daemon=True).start()
    try:
        print("\n[dashboard total_committed comes from the grid, graveyard excluded]")
        st, dash = _get(port, "/api/reports/dashboard", token)
        check(st == 200, f"GET dashboard -> 200 (got {st})")
        metrics = (dash or {}).get("data", {}).get("metrics", {})
        check(metrics.get("total_committed") == 3000000,
              f"total_committed = live grid rollup only (3,000,000; got {metrics.get('total_committed')})")
        check("total_funded" not in metrics,
              f"total_funded key dropped from metrics (got keys {sorted(metrics)})")

        print("\n[retired lp_profiles endpoints 404]")
        for path in ("/api/lp-profiles", "/api/lp-profiles/anything", "/api/reports/lp-breakdown"):
            st, _ = _get(port, path, token)
            check(st == 404, f"GET {path} -> 404 (got {st})")
    finally:
        httpd.shutdown()

    print()
    if FAILS:
        print(f"FAILED ({len(FAILS)}):")
        for f in FAILS:
            print(f"  - {f}")
        sys.exit(1)
    print("ALL PASS (dashboard KPI repoint + lp_profiles retirement)")


if __name__ == "__main__":
    main()
