"""
kinlyze/cli.py
Entry point for the `kinlyze` command.
"""

import argparse
import json
import os
import sys

from .exceptions import (
    KinlyzeError, GitNotFoundError, NotARepoError,
    EmptyRepoError, NoDataError, GitCommandError,
)
from .git import is_git_repo, get_repo_root
from .scoring import analyze_repo
from .renderer import render, print_progress, print_error, print_warning


def main() -> None:
    parser = argparse.ArgumentParser(
        prog="kinlyze",
        description="Analyze the kin behind your code — map knowledge concentration risk.",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  kinlyze                        Analyze current directory
  kinlyze --repo /path/to/repo   Analyze a specific repo
  kinlyze --days 180             Only look at last 6 months
  kinlyze --days 730             Look back 2 years
  kinlyze --top 20               Show only top 20 riskiest modules
  kinlyze --min-commits 5        Ignore files touched fewer than 5 times
  kinlyze --no-color             Plain output (pipe-friendly)
  kinlyze --json                 Raw JSON output for scripting

kinlyze.com
        """,
    )

    parser.add_argument(
        "--repo", "-r",
        default=".",
        metavar="PATH",
        help="Path to the git repository (default: current directory)",
    )
    parser.add_argument(
        "--days", "-d",
        type=int,
        default=365,
        metavar="N",
        help="Days of history to analyze (default: 365)",
    )
    parser.add_argument(
        "--top", "-t",
        type=int,
        default=None,
        metavar="N",
        help="Show only the top N riskiest modules",
    )
    parser.add_argument(
        "--min-commits",
        type=int,
        default=2,
        metavar="N",
        help="Minimum commits for a file to be included (default: 2, filters noise)",
    )
    parser.add_argument(
        "--no-color",
        action="store_true",
        help="Disable colored output",
    )
    parser.add_argument(
        "--json",
        action="store_true",
        help="Output raw JSON (disables colored terminal report)",
    )
    parser.add_argument(
        "--version", "-v",
        action="version",
        version="kinlyze 0.1.0",
    )

    args = parser.parse_args()

    # ── Apply flags ───────────────────────────────────────────────────────────
    if args.no_color or args.json:
        os.environ["NO_COLOR"] = "1"

    # ── Validate --days ───────────────────────────────────────────────────────
    if args.days < 1:
        print_error("--days must be a positive integer.")
        sys.exit(1)
    if args.days > 3650:
        print_warning("--days > 3650 may be very slow on large repositories.")

    if args.min_commits < 1:
        print_error("--min-commits must be at least 1.")
        sys.exit(1)

    # ── Validate repo path ────────────────────────────────────────────────────
    repo_path = os.path.abspath(args.repo)

    if not os.path.exists(repo_path):
        print_error(f"Path does not exist: {repo_path}")
        sys.exit(1)

    if not os.path.isdir(repo_path):
        print_error(f"Not a directory: {repo_path}")
        sys.exit(1)

    if not is_git_repo(repo_path):
        print_error(NotARepoError(repo_path).__str__())
        sys.exit(1)

    # ── Resolve repo root ─────────────────────────────────────────────────────
    try:
        repo_root = get_repo_root(repo_path)
    except GitCommandError as e:
        print_error(str(e))
        sys.exit(1)

    # ── Run analysis ──────────────────────────────────────────────────────────
    if not args.json:
        print(f"\n  Scanning {repo_root}...\n", flush=True)

    try:
        data = analyze_repo(
            repo_root,
            since_days=args.days,
            min_commits=args.min_commits,
            progress_cb=None if args.json else print_progress,
        )

    except GitNotFoundError as e:
        print_error(str(e))
        sys.exit(1)

    except EmptyRepoError as e:
        print_error(str(e))
        sys.exit(1)

    except NoDataError as e:
        print_error(str(e))
        sys.exit(1)

    except GitCommandError as e:
        print_error(str(e))
        sys.exit(1)

    except KeyboardInterrupt:
        sys.stderr.write("\n  Interrupted.\n\n")
        sys.exit(130)

    except KinlyzeError as e:
        print_error(str(e))
        sys.exit(1)

    except Exception as e:
        # Unexpected — show traceback hint so the user can report it
        print_error(
            f"Unexpected error: {type(e).__name__}: {e}\n"
            "  Please report this at: github.com/kinlyze/kinlyze/issues"
        )
        sys.exit(1)

    # ── Output ────────────────────────────────────────────────────────────────
    if args.json:
        # Serialize datetimes to ISO strings
        def _default(obj):
            if hasattr(obj, "isoformat"):
                return obj.isoformat()
            raise TypeError(f"Object of type {type(obj).__name__} is not JSON serializable")

        print(json.dumps(data, indent=2, default=_default))
    else:
        render(data, top=args.top)


if __name__ == "__main__":
    main()
