"""
report.py — Daily P&L report for MoneyMaker dry run.

Usage:
    python report.py             # full P&L report
    python report.py --fees      # fee drag analysis only
    python report.py --signals   # signal accuracy summary only
"""
import sys
import time
import json
import argparse
from datetime import datetime, timezone
from pathlib import Path

import yfinance as yf

from db import get_conn, DB_TYPE

C25_PATH = Path(__file__).parent / "c25.json"
_c25_raw = json.loads(C25_PATH.read_text())
C25: dict[str, dict] = {k: v for k, v in _c25_raw.items() if not k.startswith("_")}

CAPITAL = 10_000   # DKK — must match portfolio.py


def _c25_day_return() -> float | None:
    """Fetch today's return for OMX C25 CAP index from Yahoo Finance."""
    try:
        info = yf.Ticker("^OMXC25").fast_info
        prev  = info.get("previousClose") or info.get("regularMarketPreviousClose")
        last  = info.get("lastPrice") or info.get("regularMarketPrice")
        if prev and last and prev > 0:
            return (last - prev) / prev * 100
    except Exception:
        pass
    return None


def _unrealised_pnl(db) -> tuple[float, list[dict]]:
    """
    Calculate unrealised P&L for all open positions.
    Returns (total_unrealised_dkk, details_list).
    """
    positions = db.execute("SELECT * FROM positions").fetchall()
    details = []
    total_unreal = 0.0

    for p in positions:
        ticker     = p["ticker"]
        shares     = float(p["shares"])
        entry      = float(p["entry_price"])
        entry_date = p["entry_date"]

        yf_ticker = C25.get(ticker, {}).get("ticker_yahoo", ticker + ".CO")
        try:
            last = yf.Ticker(yf_ticker).fast_info.get("lastPrice") or entry
        except Exception:
            last = entry

        cost    = shares * entry
        value   = shares * last
        unreal  = value - cost
        pct     = (unreal / cost * 100) if cost else 0
        total_unreal += unreal

        details.append({
            "ticker":     ticker,
            "shares":     shares,
            "entry":      entry,
            "last":       last,
            "cost":       cost,
            "value":      value,
            "unreal":     unreal,
            "pct":        pct,
            "entry_date": entry_date,
        })

    return total_unreal, details


def _realised_pnl(db) -> float:
    """Sum all realised P&L from position_events."""
    row = db.execute(
        "SELECT COALESCE(SUM(pnl_dkk),0) AS total FROM position_events WHERE action='sell'"
    ).fetchone()
    return float(row["total"] or 0)


def _total_fees(db) -> float:
    """Sum all fees from saxo_orders."""
    try:
        row = db.execute(
            "SELECT COALESCE(SUM(fee_dkk),0) AS total FROM saxo_orders"
        ).fetchone()
        return float(row["total"] or 0)
    except Exception:
        return 0.0


def _invested(positions_details: list[dict]) -> float:
    return sum(p["cost"] for p in positions_details)


def _signal_accuracy(db) -> dict:
    """
    Calculate signal accuracy from completed trades (position_events).
    A signal is 'correct' if the trade had P&L > 0 (signal_correct=1).
    Also returns overall signal scan stats from article_signals.
    """
    # Accuracy from closed trades
    try:
        row = db.execute("""
            SELECT
                COUNT(*)                                          AS total_trades,
                SUM(CASE WHEN signal_correct=1 THEN 1 ELSE 0 END) AS correct,
                SUM(CASE WHEN signal_correct=0 THEN 1 ELSE 0 END) AS wrong,
                COALESCE(AVG(CASE WHEN signal_correct IS NOT NULL
                             THEN signal_correct END), -1)        AS accuracy
            FROM position_events
            WHERE action = 'sell' AND signal_correct IS NOT NULL
        """).fetchone()
        total_trades = int(row["total_trades"] or 0)
        correct      = int(row["correct"] or 0)
        wrong        = int(row["wrong"] or 0)
        accuracy_pct = (float(row["accuracy"]) * 100) if total_trades > 0 else None
    except Exception:
        total_trades = correct = wrong = 0
        accuracy_pct = None

    # NLP scan stats
    try:
        srow = db.execute("""
            SELECT
                COUNT(*) AS total_signals,
                SUM(CASE WHEN alert=1 THEN 1 ELSE 0 END) AS alerts,
                AVG(signal_score) AS avg_score
            FROM article_signals
            WHERE signal_score IS NOT NULL
        """).fetchone()
        return {
            "total":        int(srow["total_signals"] or 0),
            "alerts":       int(srow["alerts"] or 0),
            "avg_score":    round(float(srow["avg_score"] or 0), 3),
            "total_trades": total_trades,
            "correct":      correct,
            "wrong":        wrong,
            "accuracy_pct": accuracy_pct,
        }
    except Exception:
        return {
            "total": 0, "alerts": 0, "avg_score": 0,
            "total_trades": total_trades, "correct": correct,
            "wrong": wrong, "accuracy_pct": accuracy_pct,
        }


def print_report() -> None:
    db  = get_conn()
    now = datetime.now(timezone.utc).strftime("%d %b %Y  %H:%M UTC")

    unreal_total, positions = _unrealised_pnl(db)
    realised    = _realised_pnl(db)
    fees        = _total_fees(db)
    invested    = _invested(positions)
    cash        = CAPITAL - invested
    net_pnl     = realised + unreal_total - fees
    net_pct     = (net_pnl / CAPITAL * 100)
    c25_ret     = _c25_day_return()
    vs_bench    = (net_pct - c25_ret) if c25_ret is not None else None
    sig_stats   = _signal_accuracy(db)

    # ── Header ──────────────────────────────────────────────────────────────
    print()
    print("═" * 48)
    print(f"  MONEYMAKER P&L  ·  {now}")
    print(f"  DB: {DB_TYPE}")
    print("═" * 48)
    print(f"  Kapital:     {CAPITAL:>10,.0f} DKK")
    print(f"  Investeret:  {invested:>10,.0f} DKK  ({len(positions)} pos.)")
    print(f"  Kontant:     {cash:>10,.0f} DKK")
    print()
    print(f"  Urealiseret: {unreal_total:>+10,.0f} DKK")
    print(f"  Realiseret:  {realised:>+10,.0f} DKK")
    print(f"  Total gebyrer: {-fees:>+8,.0f} DKK")
    print(f"  Net P&L:     {net_pnl:>+10,.0f} DKK  ({net_pct:+.2f}%)")
    print()

    # ── Benchmark ────────────────────────────────────────────────────────────
    if c25_ret is not None:
        bench_icon = "✅" if vs_bench and vs_bench >= 0 else "❌"
        print(f"  C25 index:          {c25_ret:+.2f}%  (i dag)")
        print(f"  vs benchmark:       {vs_bench:+.2f}%  {bench_icon}")
    else:
        print("  C25 index:         N/A  (marked lukket?)")
    print()

    # ── Open positions ────────────────────────────────────────────────────────
    if positions:
        print("  ┌─ Åbne positioner ─────────────────────────────┐")
        for p in positions:
            icon = "📈" if p["unreal"] >= 0 else "📉"
            print(
                f"  │  {icon} {p['ticker']:<8}  {p['shares']:.0f} stk  "
                f"købt {p['entry']:.0f}  nu {p['last']:.0f}  "
                f"P&L {p['unreal']:+.0f} ({p['pct']:+.1f}%)"
            )
        print("  └────────────────────────────────────────────────┘")
        print()

    # ── Signal stats ─────────────────────────────────────────────────────────
    print(f"  Signaler:    {sig_stats['total']:>5}  analyseret")
    print(f"  Alerts:      {sig_stats['alerts']:>5}  ⚡ triggers")
    print(f"  Gns score:   {sig_stats['avg_score']:>5.3f}")
    if sig_stats["total_trades"] > 0:
        acc = sig_stats["accuracy_pct"]
        icon = "✅" if acc and acc >= 50 else "❌"
        print(f"  Lukkede handler: {sig_stats['total_trades']}  "
              f"({sig_stats['correct']} korrekte / {sig_stats['wrong']} forkerte)  "
              f"→ {acc:.0f}% {icon}")
    else:
        print("  Lukkede handler: 0  (ingen salg endnu)")
    if fees > 0:
        drag_pct = (fees / max(abs(net_pnl + fees), 1)) * 100
        print(f"  Gebyr-drag:  {drag_pct:.1f}% af brutto P&L")
    print("═" * 48)
    print()

    db.close()


def main():
    parser = argparse.ArgumentParser(description="MoneyMaker P&L rapport")
    parser.add_argument("--fees",    action="store_true")
    parser.add_argument("--signals", action="store_true")
    args = parser.parse_args()
    print_report()


if __name__ == "__main__":
    main()
