"""Database query commands (offline analysis of persisted data)."""

from __future__ import annotations

import os
import sqlite3
import sys
from datetime import datetime, timezone

import click


def _resolve_db_path(db: str) -> str:
    """Resolve the database path from argument or HORIZON_DB env var."""
    if db:
        return db
    return os.environ.get("HORIZON_DB", "./horizon.db")


def _format_ts(ts: float) -> str:
    """Format a UNIX timestamp as a human-readable string."""
    if ts <= 0:
        return "N/A"
    return datetime.fromtimestamp(ts, tz=timezone.utc).strftime("%Y-%m-%d %H:%M:%S")


@click.group()
def db():
    """Query the persistence database (offline analysis)."""
    pass


@db.command()
@click.option("--path", "db_path", default="", help="Path to Horizon database (or set HORIZON_DB)")
@click.option("--limit", default=50, help="Number of records to show")
@click.option("--market", default=None, help="Filter by market ID")
def fills(db_path: str, limit: int, market: str | None):
    """Show recent fills from the database."""
    path = _resolve_db_path(db_path)
    if not os.path.exists(path):
        click.echo(f"Database not found: {path}", err=True)
        sys.exit(1)

    conn = sqlite3.connect(path)
    try:
        if market:
            rows = conn.execute(
                "SELECT fill_id, order_id, market_id, side, order_side, "
                "price, size, fee, timestamp "
                "FROM fills WHERE market_id = ? ORDER BY timestamp DESC LIMIT ?",
                (market, limit),
            ).fetchall()
        else:
            rows = conn.execute(
                "SELECT fill_id, order_id, market_id, side, order_side, "
                "price, size, fee, timestamp "
                "FROM fills ORDER BY timestamp DESC LIMIT ?",
                (limit,),
            ).fetchall()

        total = conn.execute("SELECT COUNT(*) FROM fills").fetchone()[0]
    finally:
        conn.close()

    if not rows:
        click.echo("No fills found.")
        return

    click.echo(f"Fills ({len(rows)} of {total} total):\n")
    click.echo(
        f"{'Time':<20} {'Market':<22} {'Side':<5} {'Action':<5} "
        f"{'Price':>8} {'Size':>8} {'Fee':>8}"
    )
    click.echo("-" * 80)
    for row in rows:
        fill_id, order_id, market_id, side, order_side, price, size, fee, ts = row
        click.echo(
            f"{_format_ts(ts):<20} {market_id[:21]:<22} {side:<5} {order_side:<5} "
            f"{price:>8.4f} {size:>8.1f} {fee:>8.4f}"
        )


@db.command()
@click.option("--path", "db_path", default="", help="Path to Horizon database (or set HORIZON_DB)")
def positions(db_path: str):
    """Show latest position snapshot from the database."""
    path = _resolve_db_path(db_path)
    if not os.path.exists(path):
        click.echo(f"Database not found: {path}", err=True)
        sys.exit(1)

    conn = sqlite3.connect(path)
    try:
        batch_ts = conn.execute(
            "SELECT MAX(snapshot_batch) FROM position_snapshots"
        ).fetchone()[0]

        if batch_ts is None:
            click.echo("No position snapshots found.")
            return

        rows = conn.execute(
            "SELECT market_id, side, size, avg_entry_price, "
            "realized_pnl, unrealized_pnl, token_id "
            "FROM position_snapshots WHERE snapshot_batch = ?",
            (batch_ts,),
        ).fetchall()
    finally:
        conn.close()

    click.echo(f"Position snapshot from {_format_ts(batch_ts)}:\n")
    click.echo(
        f"{'Market':<22} {'Side':<5} {'Size':>8} {'AvgPrice':>10} "
        f"{'Realized':>10} {'Unrealized':>10} {'Total':>10}"
    )
    click.echo("-" * 80)
    total_realized = 0.0
    total_unrealized = 0.0
    for row in rows:
        market_id, side, size, avg_price, realized, unrealized, token_id = row
        total = realized + unrealized
        total_realized += realized
        total_unrealized += unrealized
        click.echo(
            f"{market_id[:21]:<22} {side:<5} {size:>8.1f} {avg_price:>10.4f} "
            f"${realized:>9.2f} ${unrealized:>9.2f} ${total:>9.2f}"
        )
    click.echo("-" * 80)
    click.echo(
        f"{'TOTAL':<37} {'':>8} {'':>10} "
        f"${total_realized:>9.2f} ${total_unrealized:>9.2f} "
        f"${total_realized + total_unrealized:>9.2f}"
    )


@db.command()
@click.option("--path", "db_path", default="", help="Path to Horizon database (or set HORIZON_DB)")
@click.option("--limit", default=50, help="Number of records to show")
@click.option("--open-only/--all", default=True, help="Show only open orders")
def orders(db_path: str, limit: int, open_only: bool):
    """Show orders from the database."""
    path = _resolve_db_path(db_path)
    if not os.path.exists(path):
        click.echo(f"Database not found: {path}", err=True)
        sys.exit(1)

    conn = sqlite3.connect(path)
    try:
        if open_only:
            rows = conn.execute(
                "SELECT order_id, market_id, side, order_side, price, size, "
                "filled_size, status, status_reason, recorded_at "
                "FROM order_events "
                "WHERE id IN (SELECT MAX(id) FROM order_events GROUP BY order_id) "
                "AND status IN ('new','submitted','accepted','partially_filled') "
                "ORDER BY recorded_at DESC LIMIT ?",
                (limit,),
            ).fetchall()
        else:
            rows = conn.execute(
                "SELECT order_id, market_id, side, order_side, price, size, "
                "filled_size, status, status_reason, recorded_at "
                "FROM order_events "
                "WHERE id IN (SELECT MAX(id) FROM order_events GROUP BY order_id) "
                "ORDER BY recorded_at DESC LIMIT ?",
                (limit,),
            ).fetchall()
    finally:
        conn.close()

    label = "open" if open_only else "all"
    if not rows:
        click.echo(f"No {label} orders found.")
        return

    click.echo(f"Orders ({len(rows)} {label}):\n")
    click.echo(
        f"{'Time':<20} {'Order ID':<12} {'Market':<18} {'Side':<5} "
        f"{'Action':<5} {'Price':>8} {'Size':>6} {'Filled':>6} {'Status':<16}"
    )
    click.echo("-" * 100)
    for row in rows:
        oid, mid, side, osid, price, size, filled, status, reason, ts = row
        status_str = status
        if reason:
            status_str += f" ({reason[:20]})"
        click.echo(
            f"{_format_ts(ts):<20} {oid[:11]:<12} {mid[:17]:<18} {side:<5} "
            f"{osid:<5} {price:>8.4f} {size:>6.1f} {filled:>6.1f} {status_str:<16}"
        )
