"""
Report generator — daily/weekly PnL, trade journal, and performance attribution.

Generates self-contained HTML reports that can be:
  - Viewed in browser
  - Printed to PDF (Cmd+P / Ctrl+P)
  - Emailed as HTML

Usage:
  from src.reporting.generator import generate_daily_report, generate_weekly_report
  html = generate_daily_report("2026-05-17")
"""
from __future__ import annotations

import json
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import Any

ROOT = Path(__file__).resolve().parent.parent.parent
LOGS_DIR = ROOT / "logs"
REPORTS_DIR = ROOT / "reports"
LEDGER_PATH = LOGS_DIR / "decision_ledger.ndjson"
TRADING_LEDGER_PATH = LOGS_DIR / "trading_ledger.ndjson"


def _style() -> str:
    return """
    <style>
      * { margin: 0; padding: 0; box-sizing: border-box; }
      body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; max-width: 800px; margin: 0 auto; padding: 40px 20px; color: #1a1a1a; background: #fff; }
      .header { text-align: center; padding: 40px 0; border-bottom: 3px solid #d4a017; margin-bottom: 32px; }
      .header h1 { font-size: 28px; font-weight: 700; letter-spacing: -0.5px; }
      .header .sub { font-size: 14px; color: #888; margin-top: 4px; }
      .kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; margin-bottom: 32px; }
      .kpi { background: #f8f8f8; border-radius: 8px; padding: 20px; text-align: center; border: 1px solid #e8e8e8; }
      .kpi .value { font-size: 28px; font-weight: 700; letter-spacing: -0.5px; }
      .kpi .label { font-size: 11px; color: #888; text-transform: uppercase; letter-spacing: 1px; margin-top: 4px; }
      .profit { color: #16a34a; } .loss { color: #dc2626; } .neutral { color: #6b7280; }
      table { width: 100%; border-collapse: collapse; margin: 24px 0; font-size: 13px; }
      th { text-align: left; padding: 10px 12px; background: #f5f5f5; font-weight: 600; font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; color: #888; border-bottom: 2px solid #e0e0e0; }
      td { padding: 10px 12px; border-bottom: 1px solid #f0f0f0; }
      tr:hover td { background: #fafafa; }
      .section-title { font-size: 16px; font-weight: 600; margin: 32px 0 12px; padding-bottom: 8px; border-bottom: 1px solid #e8e8e8; }
      .disclaimer { margin-top: 40px; padding: 16px; background: #fef3c7; border-radius: 6px; font-size: 11px; color: #92400e; line-height: 1.6; }
      .footer { text-align: center; margin-top: 32px; font-size: 11px; color: #ccc; }
      @media print { body { padding: 20px; } .kpi-grid { grid-template-columns: repeat(4, 1fr); } }
    </style>
    """


def _read_ledger(path: Path, since: str, until: str) -> list[dict]:
    if not path.exists():
        return []
    events = []
    try:
        for line in path.read_text(encoding="utf-8").splitlines():
            if not line.strip():
                continue
            try:
                ev = json.loads(line)
                ts = ev.get("timestamp", "")[:10]
                if since and ts < since:
                    continue
                if until and ts > until:
                    continue
                events.append(ev)
            except json.JSONDecodeError:
                continue
    except Exception:
        pass
    return events


def _compute_stats(events: list[dict]) -> dict[str, Any]:
    trades = [e for e in events if e.get("category") in ("trade_open", "trade_close", "execution_report")]
    pnl_events = [e for e in events if e.get("category") == "trade_close"]

    total_pnl = 0.0
    wins = 0
    losses = 0
    gross_profit = 0.0
    gross_loss = 0.0
    pnl_series: list[float] = []

    for e in pnl_events:
        p = float(e.get("payload", {}).get("pnl", 0) or 0)
        total_pnl += p
        pnl_series.append(total_pnl)
        if p > 0:
            wins += 1
            gross_profit += p
        else:
            losses += 1
            gross_loss += abs(p)

    total = wins + losses
    win_rate = wins / max(1, total)
    profit_factor = gross_profit / max(0.01, gross_loss)
    avg_win = gross_profit / max(1, wins)
    avg_loss = gross_loss / max(1, losses)

    # Drawdown
    peak = 0.0
    max_dd = 0.0
    for p in pnl_series:
        if p > peak:
            peak = p
        dd = peak - p
        if dd > max_dd:
            max_dd = dd

    return {
        "total_trades": total,
        "wins": wins, "losses": losses,
        "win_rate": win_rate,
        "net_pnl": total_pnl,
        "gross_profit": gross_profit,
        "gross_loss": gross_loss,
        "profit_factor": profit_factor,
        "avg_win": avg_win,
        "avg_loss": avg_loss,
        "max_drawdown": max_dd,
        "total_events": len(events),
    }


def generate_daily_report(date_str: str) -> str:
    """Generate a daily P&L report as HTML."""
    events = _read_ledger(LEDGER_PATH, date_str, date_str)
    trading = _read_ledger(TRADING_LEDGER_PATH, date_str, date_str)
    all_events = events + trading
    stats = _compute_stats(all_events)

    pnl = stats["net_pnl"]
    pnl_class = "profit" if pnl > 0 else ("loss" if pnl < 0 else "neutral")
    pnl_sign = "+" if pnl > 0 else ""

    rows = ""
    for e in reversed(all_events[-20:]):
        ts = e.get("timestamp", "")[:19]
        cat = e.get("category", "")
        p = e.get("payload", {})
        action = p.get("signal", {}).get("action", "") or p.get("action", "")
        symbol = p.get("signal", {}).get("symbol", "") or p.get("symbol", "")
        pnl_val = float(p.get("pnl", 0) or 0)
        pnl_row = f'<span class="{"profit" if pnl_val>0 else "loss"}">{pnl_val:+.2f}</span>' if pnl_val else "-"
        rows += f"<tr><td>{ts}</td><td>{cat}</td><td>{symbol}</td><td>{action}</td><td>{pnl_row}</td></tr>"

    return f"""<!DOCTYPE html><html><head><meta charset="utf-8"><title>Daily Report {date_str}</title>{_style()}</head><body>
<div class="header">
  <h1>Daily Trading Report</h1>
  <div class="sub">{date_str} — Gold AutoTrade</div>
</div>
<div class="kpi-grid">
  <div class="kpi"><div class="value {pnl_class}">{pnl_sign}{pnl:.2f}</div><div class="label">Net P&L</div></div>
  <div class="kpi"><div class="value">{stats['total_trades']}</div><div class="label">Trades</div></div>
  <div class="kpi"><div class="value">{stats['win_rate']:.0%}</div><div class="label">Win Rate</div></div>
  <div class="kpi"><div class="value">{stats['profit_factor']:.2f}</div><div class="label">Profit Factor</div></div>
  <div class="kpi"><div class="value {pnl_class}">{stats['max_drawdown']:.2f}</div><div class="label">Max Drawdown</div></div>
  <div class="kpi"><div class="value">{stats['avg_win']:.2f}</div><div class="label">Avg Win</div></div>
  <div class="kpi"><div class="value">{stats['avg_loss']:.2f}</div><div class="label">Avg Loss</div></div>
  <div class="kpi"><div class="value">{stats['total_events']}</div><div class="label">Total Events</div></div>
</div>
<div class="section-title">Recent Activity</div>
<table><thead><tr><th>Time</th><th>Category</th><th>Symbol</th><th>Action</th><th>P&L</th></tr></thead><tbody>{rows}</tbody></table>
<div class="disclaimer"><strong>Disclaimer:</strong> This report is for informational purposes only. Past performance does not guarantee future results. Trading involves substantial risk of loss.</div>
<div class="footer">Generated {datetime.now(timezone.utc).isoformat()[:19]} UTC — Gold AutoTrade</div>
</body></html>"""


def generate_weekly_report(start_date: str) -> str:
    """Generate a weekly P&L report as HTML. start_date should be a Monday."""
    end_dt = datetime.fromisoformat(start_date) + timedelta(days=6)
    end_date = end_dt.strftime("%Y-%m-%d")

    events = _read_ledger(LEDGER_PATH, start_date, end_date)
    trading = _read_ledger(TRADING_LEDGER_PATH, start_date, end_date)
    all_events = events + trading
    stats = _compute_stats(all_events)

    pnl = stats["net_pnl"]
    pnl_class = "profit" if pnl > 0 else ("loss" if pnl < 0 else "neutral")
    pnl_sign = "+" if pnl > 0 else ""

    # Group by day
    daily: dict[str, list[dict]] = {}
    for e in all_events:
        day = e.get("timestamp", "")[:10]
        daily.setdefault(day, []).append(e)

    daily_rows = ""
    for day in sorted(daily):
        ds = _compute_stats(daily[day])
        dpnl = ds["net_pnl"]
        dc = "profit" if dpnl > 0 else ("loss" if dpnl < 0 else "neutral")
        dsgn = "+" if dpnl > 0 else ""
        daily_rows += f"<tr><td>{day}</td><td>{ds['total_trades']}</td><td>{ds['win_rate']:.0%}</td><td class='{dc}'>{dsgn}{dpnl:.2f}</td></tr>"

    return f"""<!DOCTYPE html><html><head><meta charset="utf-8"><title>Weekly Report {start_date}</title>{_style()}</head><body>
<div class="header">
  <h1>Weekly Trading Report</h1>
  <div class="sub">{start_date} → {end_date} — Gold AutoTrade</div>
</div>
<div class="kpi-grid">
  <div class="kpi"><div class="value {pnl_class}">{pnl_sign}{pnl:.2f}</div><div class="label">Net P&L</div></div>
  <div class="kpi"><div class="value">{stats['total_trades']}</div><div class="label">Trades</div></div>
  <div class="kpi"><div class="value">{stats['win_rate']:.0%}</div><div class="label">Win Rate</div></div>
  <div class="kpi"><div class="value">{stats['profit_factor']:.2f}</div><div class="label">Profit Factor</div></div>
</div>
<div class="section-title">Daily Breakdown</div>
<table><thead><tr><th>Date</th><th>Trades</th><th>Win Rate</th><th>P&L</th></tr></thead><tbody>{daily_rows}</tbody></table>
<div class="disclaimer"><strong>Disclaimer:</strong> This report is for informational purposes only. Past performance does not guarantee future results. Trading involves substantial risk of loss.</div>
<div class="footer">Generated {datetime.now(timezone.utc).isoformat()[:19]} UTC — Gold AutoTrade</div>
</body></html>"""


def save_report(html: str, name: str) -> Path:
    """Save report to disk and return path."""
    REPORTS_DIR.mkdir(parents=True, exist_ok=True)
    path = REPORTS_DIR / f"{name}.html"
    path.write_text(html, encoding="utf-8")
    return path
