from datetime import date, timedelta
from typing import Optional

import typer

from ..entities.user import get_effective_organization_id
from ..utils.config import (
    ERROR_STYLE,
    INFO_STYLE,
    NOT_AVAILABLE,
)
from ..utils.utils import console, make_request, print_table, print_json, format_duration_ms, should_output_json

app = typer.Typer(help="View usage reports and billing data.")


def _usage_request(path: str, params: str) -> dict | None:
    """Make a usage API request and extract the data envelope."""
    response = make_request(f"/v1/usage/{path}?{params}")
    if response and "data" in response:
        return response["data"]
    return None


def _get_usage_report(start_date: str, end_date: str, organization_id: str = None) -> dict | None:
    """Fetch usage report for a date range."""
    params = f"startDate={start_date}&endDate={end_date}"
    if organization_id:
        params += f"&organizationId={organization_id}"
    return _usage_request("report", params)


def _get_usage_monthly(year: int, month: int, organization_id: str = None) -> dict | None:
    """Fetch usage report for a specific month."""
    params = f"year={year}&month={month}"
    if organization_id:
        params += f"&organizationId={organization_id}"
    return _usage_request("monthly", params)


def _get_usage_report_by_tags(start_date: str, end_date: str, tags: str = None, organization_id: str = None) -> dict | None:
    """Fetch usage report broken down by tags for a date range."""
    params = f"startDate={start_date}&endDate={end_date}"
    if organization_id:
        params += f"&organizationId={organization_id}"
    if tags:
        params += f"&tags={tags}"
    return _usage_request("report/by-tags", params)


def _get_usage_monthly_by_tags(year: int, month: int, tags: str = None, organization_id: str = None) -> dict | None:
    """Fetch usage report broken down by tags for a specific month."""
    params = f"year={year}&month={month}"
    if organization_id:
        params += f"&organizationId={organization_id}"
    if tags:
        params += f"&tags={tags}"
    return _usage_request("monthly/by-tags", params)


def _print_usage_report(data: dict):
    """Print a standard usage report as a table."""
    usage = data.get("usage", {})

    console.print(f"[{INFO_STYLE}]Period: {data.get('startDate', NOT_AVAILABLE)} to {data.get('endDate', NOT_AVAILABLE)}[/{INFO_STYLE}]")
    console.print(f"[{INFO_STYLE}]Total Sessions: {usage.get('totalSessions', 0)}  Total Duration: {format_duration_ms(usage.get('totalDurationMs'))}  ({usage.get('totalDurationMinutes', 0):.1f} min)[/{INFO_STYLE}]")
    console.print()

    breakdown = usage.get("agentBreakdown", [])
    if not breakdown:
        console.print(f"[{INFO_STYLE}]No usage data for this period.[/{INFO_STYLE}]")
        return

    headers = ["AGENT", "SESSIONS", "DURATION", "MINUTES"]
    rows = []
    for agent in breakdown:
        rows.append([
            agent.get("agentName", NOT_AVAILABLE),
            str(agent.get("sessionCount", 0)),
            format_duration_ms(agent.get("durationMs")),
            f"{agent.get('durationMinutes', 0):.1f}",
        ])
    print_table(headers, rows)


def _print_usage_by_tags(data: dict):
    """Print a tag-based usage report as a table."""
    console.print(f"[{INFO_STYLE}]Total Sessions: {data.get('totalSessions', 0)}  Total Duration: {format_duration_ms(data.get('totalDurationMs'))}  ({data.get('totalDurationMinutes', 0):.1f} min)[/{INFO_STYLE}]")
    console.print()

    breakdown = data.get("breakdown", [])
    if not breakdown:
        console.print(f"[{INFO_STYLE}]No usage data for this period.[/{INFO_STYLE}]")
        return

    headers = ["AGENT", "TAGS", "SESSIONS", "DURATION", "MINUTES"]
    rows = []
    for entry in breakdown:
        tags = entry.get("tags", {})
        tags_str = ", ".join(f"{k}:{v}" for k, v in tags.items()) if tags else NOT_AVAILABLE
        rows.append([
            entry.get("agentName", NOT_AVAILABLE),
            tags_str,
            str(entry.get("sessionCount", 0)),
            format_duration_ms(entry.get("durationMs")),
            f"{entry.get('durationMinutes', 0):.1f}",
        ])
    print_table(headers, rows)


@app.command("report")
def usage_report(
    start: Optional[str] = typer.Option(None, "--start", "-s", help="Start date (YYYY-MM-DD). Defaults to 30 days ago."),
    end: Optional[str] = typer.Option(None, "--end", "-e", help="End date (YYYY-MM-DD). Defaults to today."),
    by_tags: bool = typer.Option(False, "--by-tags", help="Break down usage by session tags"),
    tags: Optional[str] = typer.Option(None, "--tags", help="Filter by tags as JSON (e.g. '{\"team\":\"sales\"}')"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
    table_output: bool = typer.Option(False, "--table", "-t", help="Output as table (default for interactive terminals)"),
):
    """Show usage report for a date range."""
    organization_id = get_effective_organization_id()
    if not organization_id:
        console.print(f"[{ERROR_STYLE}]Unable to determine organization. Please sign in or set organization ID with 'vr context set-org'.[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    today = date.today()
    start_date = start or (today - timedelta(days=30)).isoformat()
    end_date = end or today.isoformat()

    if by_tags:
        data = _get_usage_report_by_tags(start_date, end_date, tags=tags, organization_id=organization_id)
    else:
        data = _get_usage_report(start_date, end_date, organization_id=organization_id)

    if not data:
        console.print(f"[{ERROR_STYLE}]Failed to fetch usage report.[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    if should_output_json(json_output, table_output):
        print_json(data)
        return

    if by_tags:
        _print_usage_by_tags(data)
    else:
        _print_usage_report(data)


@app.command("monthly")
def usage_monthly(
    year: Optional[int] = typer.Option(None, "--year", "-y", help="Year (e.g. 2026). Defaults to current year."),
    month: Optional[int] = typer.Option(None, "--month", "-m", help="Month (1-12). Defaults to current month."),
    by_tags: bool = typer.Option(False, "--by-tags", help="Break down usage by session tags"),
    tags: Optional[str] = typer.Option(None, "--tags", help="Filter by tags as JSON (e.g. '{\"team\":\"sales\"}')"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
    table_output: bool = typer.Option(False, "--table", "-t", help="Output as table (default for interactive terminals)"),
):
    """Show usage report for a specific month."""
    today = date.today()
    report_year = year or today.year
    report_month = month or today.month

    organization_id = get_effective_organization_id()
    if not organization_id:
        console.print(f"[{ERROR_STYLE}]Unable to determine organization. Please sign in or set organization ID with 'vr context set-org'.[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    if by_tags:
        data = _get_usage_monthly_by_tags(report_year, report_month, tags=tags, organization_id=organization_id)
    else:
        data = _get_usage_monthly(report_year, report_month, organization_id=organization_id)

    if not data:
        console.print(f"[{ERROR_STYLE}]Failed to fetch monthly usage report.[/{ERROR_STYLE}]")
        raise typer.Exit(1)

    if should_output_json(json_output, table_output):
        print_json(data)
        return

    if by_tags:
        _print_usage_by_tags(data)
    else:
        _print_usage_report(data)


if __name__ == "__main__":
    app()
