#!/usr/bin/env python3
"""Concatenate codebase into single processable file with path markers."""

import argparse
import os
from pathlib import Path


def should_include_file(filepath, include_patterns, exclude_patterns, exclude_dirs):
    """Check if file should be included based on patterns."""
    path_str = str(filepath)

    # Check exclude dirs
    for ex_dir in exclude_dirs:
        if ex_dir in path_str.split(os.sep):
            return False

    # Check exclude patterns
    for pattern in exclude_patterns:
        if filepath.match(pattern) or pattern in path_str:
            return False

    # Check include patterns
    if include_patterns:
        for pattern in include_patterns:
            if filepath.match(pattern) or path_str.endswith(pattern):
                return True
        return False

    return True


def concatenate_codebase(
    source_dir,
    output_file,
    include_patterns=None,
    exclude_patterns=None,
    exclude_dirs=None,
):
    """
    Concatenate all code files into single file with path markers.

    Format:
    ======== FILE: /path/to/file.py ========
    <content>
    ======== END FILE ========
    """
    if include_patterns is None:
        include_patterns = [
            "*.py",
            "*.js",
            "*.ts",
            "*.jsx",
            "*.tsx",
            "*.java",
            "*.go",
            "*.rs",
            "*.c",
            "*.cpp",
            "*.h",
            "*.md",
            "*.yaml",
            "*.yml",
            "*.json",
            "*.toml",
            "*.sh",
            "*.Dockerfile",
        ]

    if exclude_patterns is None:
        exclude_patterns = ["*.min.js", "*.min.css", "*.lock", "*.sum"]

    if exclude_dirs is None:
        exclude_dirs = [
            ".git",
            "node_modules",
            "__pycache__",
            ".venv",
            "venv",
            "dist",
            "build",
            ".pytest_cache",
            ".mypy_cache",
            ".tox",
            ".coverage",
            "htmlcov",
            ".eggs",
            "*.egg-info",
        ]

    source_path = Path(source_dir).resolve()
    files_processed = 0
    total_lines = 0
    total_bytes = 0

    with open(output_file, "w", encoding="utf-8") as outf:
        # Write header
        outf.write(f"# Codebase: {source_path.name}\n")
        outf.write(f"# Source: {source_path}\n")
        outf.write("# Generated by: codebase_concat.py\n")
        outf.write("#\n# Format: ======== FILE: <path> ========\n")
        outf.write("#         <content>\n")
        outf.write("#         ======== END FILE ========\n#\n\n")

        for filepath in sorted(source_path.rglob("*")):
            if not filepath.is_file():
                continue

            rel_path = filepath.relative_to(source_path)

            if not should_include_file(
                filepath, include_patterns, exclude_patterns, exclude_dirs
            ):
                continue

            try:
                with open(filepath, encoding="utf-8", errors="ignore") as inf:
                    content = inf.read()

                if not content.strip():
                    continue

                # Write file marker and content
                outf.write(f"\n{'=' * 60}\n")
                outf.write(f"FILE: {rel_path}\n")
                outf.write(f"{'=' * 60}\n\n")
                outf.write(content)
                outf.write(f"\n\n{'=' * 60}\n")
                outf.write(f"END FILE: {rel_path}\n")
                outf.write(f"{'=' * 60}\n")

                files_processed += 1
                total_lines += content.count("\n")
                total_bytes += len(content.encode("utf-8"))

            except Exception as e:
                print(f"Warning: Could not process {rel_path}: {e}")

    print("Codebase concatenation complete:")
    print(f"  Files: {files_processed}")
    print(f"  Lines: {total_lines:,}")
    print(f"  Size: {total_bytes / (1024 * 1024):.2f} MB")
    print(f"  Output: {output_file}")

    return {
        "files": files_processed,
        "lines": total_lines,
        "bytes": total_bytes,
        "output": output_file,
    }


def extract_file_from_concat(concat_file, target_path, output_file=None):
    """Extract a specific file from concatenated codebase."""
    if output_file is None:
        output_file = target_path.replace("/", "_")

    with open(concat_file) as f:
        content = f.read()

    # Find the file section
    pattern = f"======== FILE: {target_path} ========\n(.*?)======== END FILE"
    import re

    match = re.search(pattern, content, re.DOTALL)

    if match:
        with open(output_file, "w") as f:
            f.write(match.group(1))
        print(f"Extracted: {target_path} -> {output_file}")
        return True
    else:
        print(f"File not found: {target_path}")
        return False


def main():
    parser = argparse.ArgumentParser(
        description="Concatenate codebase into single processable file"
    )
    parser.add_argument("source_dir", help="Source directory to process")
    parser.add_argument(
        "-o",
        "--output",
        default="codebase_concat.txt",
        help="Output file (default: codebase_concat.txt)",
    )
    parser.add_argument(
        "-i", "--include", nargs="+", help="Include patterns (e.g., *.py *.js)"
    )
    parser.add_argument("-e", "--exclude", nargs="+", help="Exclude patterns")
    parser.add_argument("--exclude-dirs", nargs="+", help="Exclude directories")
    parser.add_argument(
        "--extract",
        metavar="PATH",
        help="Extract specific file from concatenated output",
    )

    args = parser.parse_args()

    if args.extract:
        extract_file_from_concat(args.output, args.extract)
    else:
        concatenate_codebase(
            args.source_dir,
            args.output,
            include_patterns=args.include,
            exclude_patterns=args.exclude,
            exclude_dirs=args.exclude_dirs,
        )


if __name__ == "__main__":
    main()
