"""CLI for the DataTools reconciliation tool.

Usage:
    python -m src.cli_reconcile bank.csv ledger.csv \\
        --left-amount amount --right-amount amt \\
        --left-date date --right-date posted             # dry-run preview
    python -m src.cli_reconcile bank.csv ledger.csv \\
        --left-amount amount --right-amount amt \\
        --left-date date --right-date posted --apply     # write matched/unmatched CSVs
    python -m src.cli_reconcile --help                   # full help

Outputs (with --apply) sit beside the LEFT input file:
    {stem}_matched.csv           one row per accepted pair
    {stem}_unmatched_left.csv    left rows with no counterpart
    {stem}_unmatched_right.csv   right rows with no counterpart
    {stem}_review.csv            ambiguous pairs flagged for review
"""

from __future__ import annotations

import sys
from datetime import datetime
from pathlib import Path
from typing import Optional

import typer
from loguru import logger

app = typer.Typer(
    name="reconcile",
    help=(
        "Reconcile two data sources (e.g. bank feed vs. ledger export).\n\n"
        "By default, runs in preview mode — shows the match stats without "
        "writing anything. Add --apply to write the four output CSVs.\n\n"
        "Examples:\n\n"
        "  # Bank feed vs ledger, exact match\n"
        "  python -m src.cli_reconcile bank.csv ledger.csv \\\n"
        "      --left-amount amount --right-amount amt \\\n"
        "      --left-date date --right-date posted\n\n"
        "  # Allow 2-day posting drift and a cent of rounding tolerance\n"
        "  python -m src.cli_reconcile bank.csv ledger.csv \\\n"
        "      --left-amount amount --right-amount amt \\\n"
        "      --left-date date --right-date posted \\\n"
        "      --date-tolerance 2 --amount-tolerance 0.01 --apply\n\n"
        "  # Bank shows debits as positive; ledger as negative\n"
        "  python -m src.cli_reconcile bank.csv ledger.csv \\\n"
        "      --left-amount amount --right-amount amt --invert-right-sign --apply\n"
    ),
    add_completion=False,
    no_args_is_help=True,
)


def _setup_logging(log_dir: Path) -> Path:
    log_dir.mkdir(parents=True, exist_ok=True)
    ts = datetime.now().strftime("%Y%m%d_%H%M%S")
    log_path = log_dir / f"reconcile_{ts}.log"
    logger.remove()
    logger.add(sys.stderr, level="WARNING", format="{message}")
    logger.add(
        str(log_path),
        level="DEBUG",
        format="{time:YYYY-MM-DD HH:mm:ss} | {level:<8} | {message}",
    )
    return log_path


def _split_csv_arg(raw: Optional[str]) -> list[str]:
    if raw is None:
        return []
    return [c.strip() for c in raw.split(",") if c.strip()]


@app.command()
def run(
    left_file: str = typer.Argument(..., help="Path to the LEFT input (e.g. bank feed)."),
    right_file: str = typer.Argument(..., help="Path to the RIGHT input (e.g. ledger)."),
    left_amount: str = typer.Option(..., "--left-amount", help="Amount column on the LEFT."),
    right_amount: str = typer.Option(..., "--right-amount", help="Amount column on the RIGHT."),
    left_date: Optional[str] = typer.Option(None, "--left-date", help="Date column on the LEFT."),
    right_date: Optional[str] = typer.Option(None, "--right-date", help="Date column on the RIGHT."),
    left_keys: Optional[str] = typer.Option(
        None, "--left-keys",
        help="Comma-separated reference/key columns on the LEFT (paired with --right-keys).",
    ),
    right_keys: Optional[str] = typer.Option(
        None, "--right-keys",
        help="Comma-separated reference/key columns on the RIGHT (paired with --left-keys).",
    ),
    left_desc: Optional[str] = typer.Option(None, "--left-desc", help="Description column on the LEFT (fuzzy)."),
    right_desc: Optional[str] = typer.Option(None, "--right-desc", help="Description column on the RIGHT (fuzzy)."),
    desc_min_score: int = typer.Option(
        0, "--desc-min-score",
        help="Min description similarity (0-100) to accept a fuzzy match. 0 disables.",
    ),
    amount_tolerance: float = typer.Option(
        0.0, "--amount-tolerance",
        help="Absolute amount tolerance (e.g. 0.01 to absorb cent-rounding).",
    ),
    date_tolerance: int = typer.Option(
        0, "--date-tolerance",
        help="Date tolerance in calendar days (± N).",
    ),
    invert_right_sign: bool = typer.Option(
        False, "--invert-right-sign",
        help="Negate the RIGHT amount before matching (use when sign conventions differ).",
    ),
    apply: bool = typer.Option(
        False, "--apply",
        help="Write the four output CSV files. Without this flag, only stats are shown.",
    ),
):
    """Reconcile two CSV/Excel files."""
    from src.core.io import read_file, write_file
    from src.core.reconcile import ReconcileOptions, reconcile

    left_path = Path(left_file)
    right_path = Path(right_file)
    for p in (left_path, right_path):
        if not p.exists():
            typer.echo(f"Error: File not found: {p}", err=True)
            raise typer.Exit(1)

    log_path = _setup_logging(Path("logs"))

    typer.echo(f"Reading {left_path.name}...")
    try:
        left_df = read_file(left_path)
    except Exception as e:
        typer.echo(f"Error reading {left_path.name}: {e}", err=True)
        raise typer.Exit(1)
    typer.echo(f"  {len(left_df)} rows, {len(left_df.columns)} columns")

    typer.echo(f"Reading {right_path.name}...")
    try:
        right_df = read_file(right_path)
    except Exception as e:
        typer.echo(f"Error reading {right_path.name}: {e}", err=True)
        raise typer.Exit(1)
    typer.echo(f"  {len(right_df)} rows, {len(right_df.columns)} columns")

    options = ReconcileOptions(
        left_amount=left_amount,
        right_amount=right_amount,
        left_date=left_date,
        right_date=right_date,
        left_keys=_split_csv_arg(left_keys),
        right_keys=_split_csv_arg(right_keys),
        left_desc=left_desc,
        right_desc=right_desc,
        desc_min_score=desc_min_score,
        amount_tolerance=amount_tolerance,
        date_tolerance_days=date_tolerance,
        invert_right_sign=invert_right_sign,
    )

    typer.echo("Reconciling...")
    try:
        result = reconcile(left_df, right_df, options)
    except ValueError as e:
        typer.echo(f"Error: {e}", err=True)
        raise typer.Exit(1)

    _print_stats(result.stats)

    if apply:
        stem = left_path.stem
        out_dir = left_path.parent
        write_file(result.matched, out_dir / f"{stem}_matched.csv")
        write_file(result.unmatched_left, out_dir / f"{stem}_unmatched_left.csv")
        write_file(result.unmatched_right, out_dir / f"{stem}_unmatched_right.csv")
        write_file(result.review, out_dir / f"{stem}_review.csv")
        typer.echo(f"\nWrote 4 files to {out_dir}:")
        for suffix in ("matched", "unmatched_left", "unmatched_right", "review"):
            typer.echo(f"  {stem}_{suffix}.csv")
    else:
        typer.echo("\nThis was a preview. Add --apply to write the output files.")

    typer.echo(f"Log: {log_path}")


def _print_stats(stats: dict) -> None:
    typer.echo(f"\n{'─'*50}")
    typer.echo(f"  Left rows:           {stats['left_rows']}")
    typer.echo(f"  Right rows:          {stats['right_rows']}")
    typer.echo(f"  Matched:             {stats['matched']}")
    typer.echo(f"  Review (ambiguous):  {stats['review']}")
    typer.echo(f"  Unmatched left:      {stats['unmatched_left']}")
    typer.echo(f"  Unmatched right:     {stats['unmatched_right']}")
    typer.echo(f"{'─'*50}")


def main():
    app()


if __name__ == "__main__":
    main()
