"""Clone architectural pattern from a repo into a new directory."""
from __future__ import annotations

import time
from pathlib import Path
from dataclasses import dataclass, field

from kodara.remote.scanner import scan_remote  # noqa: F401  (re-exported for patching)
from kodara.dna.fingerprint import build_fingerprint  # noqa: F401
from kodara.memory.store import KodaraIndex


@dataclass
class CloneResult:
    source: str
    target: str
    dirs_created: list[str] = field(default_factory=list)
    files_created: list[str] = field(default_factory=list)
    patterns_applied: list[str] = field(default_factory=list)
    error: str | None = None


# Pattern category → (subdirectory, files_to_create)
_PATTERN_MAP: dict[str, tuple[str, list[str]]] = {
    "Auth":     ("auth",   ["middleware.py", "models.py"]),
    "Routing":  ("routes", ["__init__.py"]),
    "Database": ("db",     ["models.py", "repository.py"]),
    "Caching":  ("cache",  ["client.py"]),
    "Queue":    ("queue",  ["tasks.py"]),
    "Testing":  ("tests",  ["conftest.py"]),
}


def _comment(url: str) -> str:
    return f"# Generated by kodara clone-pattern from {url}\n"


def clone_pattern(url: str, target_dir: str) -> CloneResult:
    """
    1. Use scan_remote to scan the source repo
    2. Use build_fingerprint() to get ProjectDNA
    3. Map DNA patterns to directory structure
    4. Create dirs + empty placeholder files in target_dir
    5. Return CloneResult
    """
    result = CloneResult(source=url, target=target_dir)

    try:
        target = Path(target_dir)

        # Guard: target must not exist and be non-empty
        if target.exists() and any(target.iterdir()):
            result.error = "Target directory is not empty"
            return result

        # Scan the source repo
        scan_summary = scan_remote(url)

        # Build a minimal KodaraIndex so build_fingerprint can work
        index = KodaraIndex(
            repo_id=f"clone/{url}",
            display_name=url,
            source_root="",
            indexed_at=time.time(),
            index_version=1,
            file_count=scan_summary.file_count,
            language_counts=scan_summary.language_counts,
            modules={},
            graph_edges=[],
            file_hashes={},
        )

        dna = build_fingerprint(index)

        # Create target directory
        target.mkdir(parents=True, exist_ok=True)

        comment = _comment(url)

        def _make_file(rel_path: str) -> None:
            abs_path = target / rel_path
            abs_path.parent.mkdir(parents=True, exist_ok=True)
            abs_path.write_text(comment, encoding="utf-8")
            result.files_created.append(str(abs_path))

        def _make_dir(rel_dir: str) -> None:
            abs_dir = target / rel_dir
            abs_dir.mkdir(parents=True, exist_ok=True)
            result.dirs_created.append(str(abs_dir))

        # Always-present base structure
        for base_file in ["main.py", "config.py", "requirements.txt", "README.md"]:
            _make_file(base_file)

        # Override README content with a more descriptive message
        readme_path = target / "README.md"
        readme_path.write_text(
            f"# Generated by Kodara clone-pattern\n\n{comment}",
            encoding="utf-8",
        )

        # Pattern-driven structure
        patterns_applied: list[str] = []

        for category, pattern_names in dna.detected_patterns.items():
            if not pattern_names:
                continue

            mapping = _PATTERN_MAP.get(category)
            if mapping is None:
                continue

            subdir, files = mapping
            _make_dir(subdir)
            for fname in files:
                _make_file(f"{subdir}/{fname}")

            # Collect human-readable pattern names that were actually detected
            for pname in pattern_names:
                if pname not in patterns_applied:
                    patterns_applied.append(pname)

        result.patterns_applied = patterns_applied

    except Exception as exc:  # noqa: BLE001
        result.error = str(exc)

    return result
