"""CLI command for detecting duplicate groups in a dataset."""

from __future__ import annotations

import argparse
import sys
import termios
import tty
from collections.abc import Sequence
from pathlib import Path

import polars as pl

from ..api import Runtime
from ..duplicates import duplicates_paths, parse_name_list
from ..logging import Recorder, RecorderConfig
from ..utils import _boot_trace
from .progress import file_write_feedback


def duplicates_main(argv: Sequence[str], *, command_name: str = "duplicates") -> int:
    _boot_trace("cli:duplicates start")
    parser = _build_parser(command_name)
    args = parser.parse_args(argv)

    runtime = Runtime()
    try:
        keys = parse_name_list(args.keys)
        cols = parse_name_list(args.cols)
        exclude = parse_name_list(args.exclude)
        try:
            rows_mode = not args.groups
            result = duplicates_paths(
                runtime,
                args.path,
                keys=keys,
                cols=cols,
                exclude=exclude,
                rows=rows_mode,
            )
        except ValueError as exc:
            parser.error(str(exc))
        duplicates_lf = result.duplicates_lf
        summary = result.summary

        if args.out:
            exit_code = _write_duplicates_output(duplicates_lf, args.out)
            _print_summary(summary)
            return _final_exit_code(exit_code, summary)

        _print_summary(summary)
        if _should_open_tui():
            return _open_duplicates_tui(runtime, duplicates_lf, summary)
        return _final_exit_code(0, summary)
    finally:
        runtime.close()


def _build_parser(command_name: str) -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(
        prog=f"pulka {command_name}",
        description="Detect duplicates in a dataset and open a duplicate view",
    )
    parser.add_argument("path", help="Dataset path")
    parser.add_argument(
        "--keys",
        help="Comma-separated key columns (included in detection when --cols is provided)",
    )
    parser.add_argument(
        "--cols",
        help="Comma-separated columns to consider for duplicate detection (default: all columns)",
    )
    parser.add_argument(
        "--exclude",
        help="Comma-separated columns to exclude from duplicate detection",
    )
    parser.add_argument(
        "--groups",
        action="store_true",
        help="Return one row per duplicate group instead of all duplicated rows",
    )
    parser.add_argument(
        "--out",
        type=Path,
        help="Write duplicate output to PATH and exit",
    )
    return parser


def _write_duplicates_output(duplicates_lf: pl.LazyFrame, destination: Path) -> int:
    from ..data.export import write_view_to_path

    try:
        with file_write_feedback(destination, noun="duplicates file"):
            write_view_to_path(duplicates_lf, destination)
    except Exception as exc:
        print(f"Export failed: {exc}", file=sys.stderr)
        return 2
    print(f"Wrote {destination}")
    return 0


def _should_open_tui() -> bool:
    if not sys.stdin.isatty():
        return False
    return _prompt_yes_no("Open duplicate groups sheet in Pulka? [y/n] ")


def _prompt_yes_no(prompt: str) -> bool:
    fd = sys.stdin.fileno()
    try:
        old_settings = termios.tcgetattr(fd)
    except Exception:
        try:
            response = input(prompt).strip().lower()
        except EOFError:
            return False
        return response in {"", "y", "yes"}

    sys.stdout.write("\n")
    sys.stdout.write(prompt)
    sys.stdout.flush()
    try:
        tty.setraw(fd)
        char = sys.stdin.read(1)
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)

    sys.stdout.write("\n")
    sys.stdout.flush()
    if not char:
        return False
    return char.lower() in {"y", "\r", "\n"}


def _open_duplicates_tui(
    runtime: Runtime,
    duplicates_lf: pl.LazyFrame,
    summary: dict[str, object],
) -> int:
    from ..tui.app import run_tui_app

    source_label = f"duplicates: {summary['dataset_path']}"
    recorder = Recorder(RecorderConfig(enabled=False))
    session = runtime.open(
        None,
        recorder=recorder,
        lazyframe=duplicates_lf,
        source_label=source_label,
    )
    session.viewer.status_message = (
        f"duplicates: groups={summary['dupe_groups']} rows={summary['dupe_rows']}"
    )
    try:
        run_tui_app(session.viewer, recorder=session.recorder)
    finally:
        session.close()
    return _final_exit_code(0, summary)


def _final_exit_code(base: int, summary: dict[str, object]) -> int:
    if base:
        return base
    return 0 if int(summary.get("dupe_groups", 0)) == 0 else 1


def _print_summary(summary: dict[str, object]) -> None:
    for warning in summary.get("warnings") or ():
        text = str(warning).strip()
        if text:
            print(f"warning: {text}", file=sys.stderr)

    dataset_path = summary["dataset_path"]
    detection_cols = summary["detection_cols"]
    excluded_cols = summary.get("exclude") or []
    total_rows = int(summary["total_rows"])
    dupe_groups = int(summary["dupe_groups"])
    dupe_rows = int(summary["dupe_rows"])
    dupe_extra_rows = int(summary["dupe_extra_rows"])
    rows_mode = bool(summary.get("rows_mode", False))

    detection_text = ", ".join(detection_cols)
    print("Duplicates summary")
    print(f"  path: {dataset_path}")
    print(f"  detection columns: {detection_text}")
    if excluded_cols:
        print(f"  excluded columns: {', '.join(excluded_cols)}")
    print(f"  output mode: {'rows' if rows_mode else 'groups'}")
    print(f"  total rows: {total_rows}")
    print(f"  duplicate groups: {dupe_groups}")
    print(f"  duplicate rows: {dupe_rows}")
    print(f"  extra rows beyond first per group: {dupe_extra_rows}")


__all__ = ["duplicates_main"]
