"""
Remote Scanner — clones a remote git repo into a temp directory,
scans it with RepositoryScanner, and returns a ScanSummary.

Supported URL formats:
  github.com/user/repo           -> https://github.com/user/repo
  https://github.com/user/repo  -> used as-is
  /absolute/path or ./rel/path  -> local scan (no clone)
"""

from __future__ import annotations

import shutil
import subprocess
import tempfile
import time
from dataclasses import dataclass, field
from pathlib import Path


@dataclass
class ScanSummary:
    """Result of a remote (or local) scan operation."""
    url: str
    file_count: int
    language_counts: dict
    top_modules: list[str]      # hub modules (top 5 by in-degree)
    scan_time_s: float


def parse_url(url: str) -> tuple[str, bool]:
    """
    Normalise user input into (resolved_url, is_remote).

    Returns:
        (https_url, True)   -- for remote repos
        (local_path, False) -- for local paths
    """
    stripped = url.strip()

    # Local path: starts with ./ ../ / \ or Windows drive letter (C:\)
    if (
        stripped.startswith("./")
        or stripped.startswith("../")
        or stripped.startswith("/")
        or stripped.startswith("\\")
        or (len(stripped) >= 2 and stripped[1] == ":")
    ):
        return stripped, False

    # Already a full URL
    if stripped.startswith("https://") or stripped.startswith("http://"):
        return stripped, True

    # Bare "github.com/user/repo" style
    if "/" in stripped:
        return f"https://{stripped}", True

    # Fallback: treat as local
    return stripped, False


def _git_available() -> bool:
    """Return True if git is on PATH."""
    try:
        result = subprocess.run(
            ["git", "--version"],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            timeout=10,
        )
        return result.returncode == 0
    except (FileNotFoundError, subprocess.TimeoutExpired):
        return False


def _build_modules_dict(scan) -> dict[str, dict]:
    """Build a minimal modules dict from a ScanResult for heuristic summaries."""
    modules: dict[str, dict] = {}
    for file_path, info in scan.files.items():
        modules[file_path] = {
            "path": file_path,
            "language": info.language,
            "classes": info.classes,
            "functions": info.functions,
            "exports": info.exports,
            "imports": info.imports,
            "summary": "",
        }
    return modules


def scan_remote(url: str) -> ScanSummary:
    """
    Clone (if remote) and scan a repository.

    Args:
        url: github.com/user/repo, https://..., or a local path.

    Returns:
        ScanSummary with statistics.

    Raises:
        ValueError: if git is not installed or cloning fails.
    """
    from kodara.indexer.scanner import RepositoryScanner
    from kodara.graph.dependency import DependencyGraph
    from kodara.summarizer import generate_summaries

    resolved_url, is_remote = parse_url(url)
    t0 = time.time()

    tmp_dir: str | None = None

    try:
        if is_remote:
            if not _git_available():
                raise ValueError(
                    "git is not installed or not on PATH. "
                    "Install git to use remote scanning."
                )

            tmp_dir = tempfile.mkdtemp(prefix="kodara_remote_")
            result = subprocess.run(
                ["git", "clone", "--depth=1", resolved_url, tmp_dir],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                timeout=300,
            )
            if result.returncode != 0:
                stderr_msg = result.stderr.decode("utf-8", errors="replace").strip()
                raise ValueError(
                    f"git clone failed (exit {result.returncode}): {stderr_msg}"
                )
            scan_root = tmp_dir
        else:
            scan_root = str(Path(resolved_url).resolve())

        # Scan
        scanner = RepositoryScanner(scan_root)
        scan = scanner.scan(free_plan=True)

        # Build dependency graph
        graph = DependencyGraph()
        graph.build(scan)

        # Heuristic-only summaries (no AI to keep remote scan fast)
        # Pass api_key=None explicitly so heuristic branch is always taken
        modules_dict = _build_modules_dict(scan)
        generate_summaries(modules_dict, api_key=None)

        # Top hub modules (by in-degree, top 5)
        hub_pairs = graph.get_hub_modules(top_n=5)
        top_modules: list[str] = []
        for path, degree in hub_pairs:
            if degree > 0:
                module_name = graph.node_data(path).get("module_name") or path
                top_modules.append(module_name)

        scan_time_s = round(time.time() - t0, 2)

        return ScanSummary(
            url=url,
            file_count=len(scan.files),
            language_counts=dict(scan.languages),
            top_modules=top_modules,
            scan_time_s=scan_time_s,
        )

    finally:
        if tmp_dir is not None and Path(tmp_dir).exists():
            try:
                shutil.rmtree(tmp_dir, ignore_errors=True)
            except Exception:
                pass
