"""
Main initialization module for Synapsis DSAI Agent Rules.

This module provides the core functionality for initializing agent rules by
copying template directories (.agent, .agents, .claude, .cursor, .github) from the package
into the user's current working directory, with support for language and domain selection.

Functions:
    run(): Main entry point for the initialization CLI tool.
"""

import shutil
import sys
import argparse
import re
from pathlib import Path
from importlib.resources import files

# Marker to identify files managed by this tool at the user side
MANAGED_MARKER = "<!-- synapsis-dsai-managed -->"

# Full mapping of tools to their respective folders and files
TOOL_MAPPING = {
    "1": {"name": "Gemini CLI", "folders": [".agent"], "files": ["GEMINI.md"]},
    "2": {"name": "Claude Code", "folders": [".claude"], "files": ["CLAUDE.md"]},
    "3": {"name": "Cursor AI", "folders": [".cursor"], "files": [".cursorrules"]},
    "4": {"name": "GitHub Copilot", "folders": [".github"], "files": ["AGENTS.md"]},
    "5": {"name": "Google Antigravity", "folders": [".agents"], "files": []}
}

# Mapping of programming languages
LANGUAGE_MAPPING = {
    "1": {"name": "Python", "id": "python"},
    "2": {"name": "Rust", "id": "rust"},
    "3": {"name": "Go", "id": "go"},
    "4": {"name": "JavaScript/TypeScript", "id": "js"},
    "5": {"name": "C++", "id": "cpp"}
}

START_MARKER = "<!-- synapsis-dsai-core-start -->"
END_MARKER = "<!-- synapsis-dsai-core-end -->"

# Extensions that should be treated as text and receive markers
TEXT_EXTENSIONS = {'.md', '.mdc', '.txt', '.json', '.yaml', '.yml', '.py', '.sh', '.ps1'}


def _get_template_path() -> Path:
    """
    Retrieve the path to the package's templates directory.
    """
    return files("dsai_synapsis_agent_init") / "templates"


def _update_standalone_file(target_path: Path, template_block: str) -> None:
    """
    Safely injects or updates the Synapsis Core Block in a standalone file.
    """
    file_name = target_path.name
    
    if not target_path.exists():
        try:
            target_path.write_text(template_block, encoding="utf-8")
            print(f"✅ Berhasil membuat {file_name}")
            return
        except Exception as e:
            print(f"❌ Gagal membuat {file_name}: {e}")
            return

    content = target_path.read_text(encoding="utf-8")
    
    start_idx = content.find(START_MARKER)
    end_idx = content.find(END_MARKER)

    if start_idx != -1 and end_idx != -1:
        if start_idx > end_idx:
            print(f"⚠️  Marker di {file_name} rusak (Start setelah End). Melewati auto-update.")
            return
            
        new_content = content[:start_idx] + template_block.strip() + content[end_idx + len(END_MARKER):]
        if content != new_content:
            target_path.write_text(new_content, encoding="utf-8")
            print(f"🔄 Berhasil memperbarui blok standar di {file_name}")
        else:
            print(f"✨ Blok standar di {file_name} sudah versi terbaru.")
    elif start_idx == -1 and end_idx == -1:
        new_content = content.rstrip() + "\n\n" + template_block.strip() + "\n"
        target_path.write_text(new_content, encoding="utf-8")
        print(f"➕ Berhasil menambahkan blok standar ke {file_name}")
    else:
        print(f"⚠️  Tag pembatas di {file_name} tidak lengkap. Melewati auto-update untuk keamanan.")


def _inject_managed_marker(content: str, file_name: str) -> str:
    """
    Injects the managed marker into the content based on file type.
    """
    if MANAGED_MARKER in content:
        return content

    # For SKILL.md with frontmatter, insert after the second ---
    if file_name.upper() == "SKILL.MD" and content.strip().startswith("---"):
        match = re.search(r'^---\s*.*?\s*---', content, re.DOTALL | re.MULTILINE)
        if match:
            sep_end = match.end()
            return content[:sep_end] + "\n" + MANAGED_MARKER + "\n" + content[sep_end:].lstrip()
    
    # Default for rules/workflows/others: Append to BOTTOM
    return f"{content.rstrip()}\n\n{MANAGED_MARKER}\n"


def _sync_file(source: Path, destination: Path, verbose: bool = False) -> None:
    """
    Syncs a single file from source to destination using dynamic ownership rules.
    """
    file_name = destination.name
    try:
        source_raw_content = source.read_text(encoding="utf-8")
    except Exception:
        # For non-text/binary files, just copy
        try:
            destination.parent.mkdir(parents=True, exist_ok=True)
            shutil.copy2(str(source), str(destination))
            if verbose: print(f"✨ Synced asset: {file_name}")
            return
        except Exception as e:
            print(f"❌ Gagal menyalin asset {file_name}: {e}")
            return
    
    target_content = _inject_managed_marker(source_raw_content, file_name)

    if not destination.exists():
        try:
            destination.parent.mkdir(parents=True, exist_ok=True)
            destination.write_text(target_content, encoding="utf-8")
            if verbose: print(f"🆕 Created: {file_name}")
            return
        except Exception as e:
            print(f"❌ Gagal membuat {file_name}: {e}")
            return

    try:
        dest_current_content = destination.read_text(encoding="utf-8")
        if MANAGED_MARKER in dest_current_content:
            if dest_current_content.strip() != target_content.strip():
                destination.write_text(target_content, encoding="utf-8")
                if verbose: print(f"🔄 Updating managed file: {file_name}")
            elif verbose:
                print(f"✨ Already up-to-date: {file_name}")
        else:
            if verbose: print(f"⏭️  Skipping customized file: {file_name}")
    except Exception as e:
        print(f"❌ Error syncing {file_name}: {e}")


def _sync_template_folder(source: Path, destination: Path, verbose: bool = False) -> None:
    """
    Recursively syncs a template folder using the ownership marker system.
    """
    source_path = Path(str(source))
    if not source_path.exists():
        if verbose: print(f"⚠️  Template path {source} tidak ditemukan.")
        return

    # Iterate over items in the source folder
    for item in source_path.iterdir():
        if item.is_dir():
            # item is a skill folder (e.g., 'brainstorming')
            # we want to sync it recursively to destination / item.name
            dest_subdir = destination / item.name
            for src_file in item.rglob('*'):
                if src_file.is_file():
                    rel_file_path = src_file.relative_to(item)
                    dest_file = dest_subdir / rel_file_path
                    _sync_file(src_file, dest_file, verbose)
        elif item.is_file():
            # If item is a file (e.g., in .agent/rules/), sync it directly to destination
            _sync_file(item, destination / item.name, verbose)


def run() -> None:
    """
    Initialize Synapsis DSAI Agent Rules in the current working directory.
    """
    parser = argparse.ArgumentParser(description="Initialize Synapsis DSAI Agent Rules.")
    parser.add_argument("--verbose", action="store_true", help="Show detailed sync information.")
    parser.add_argument("--all", action="store_true", help="Initialize all AI agent tools and all languages without asking.")
    parser.add_argument("-y", "--yes", action="store_true", help="Skip confirmation.")
    args = parser.parse_args()

    print("🚀 [Synapsis DSAI] Initializing agent rules...")

    # Step 1: Tool selection
    selected_tools = []
    if args.all or args.yes:
        selected_tools = list(TOOL_MAPPING.values())
    else:
        print("\nAI agent apa saja yang Anda gunakan? (Pisahkan dengan koma, misal: 1,3)")
        for key, tool in TOOL_MAPPING.items():
            print(f" {key}. {tool['name']}")
        
        try:
            choice = input("\nPilihan Anda (kosongkan untuk semua): ").strip()
            if not choice:
                selected_tools = list(TOOL_MAPPING.values())
            else:
                choices = [c.strip() for c in choice.split(",")]
                for c in choices:
                    if c in TOOL_MAPPING:
                        selected_tools.append(TOOL_MAPPING[c])
                    else:
                        print(f"⚠️  Pilihan tool '{c}' tidak valid, dilewati.")
        except EOFError:
            selected_tools = list(TOOL_MAPPING.values())

    if not selected_tools:
        print("❌ Tidak ada tool yang dipilih. Membatalkan.")
        return

    # Step 2: Language selection
    selected_langs = []
    if args.all:
        selected_langs = list(LANGUAGE_MAPPING.values())
    elif args.yes:
        selected_langs = [LANGUAGE_MAPPING["1"]] # Default to Python
    else:
        print("\nLanguage stack apa yang digunakan? (Pisahkan dengan koma, misal: 1,2)")
        for key, lang in LANGUAGE_MAPPING.items():
            print(f" {key}. {lang['name']}")
        
        try:
            choice = input("\nPilihan Anda (kosongkan untuk Python): ").strip()
            if not choice:
                selected_langs = [LANGUAGE_MAPPING["1"]]
            else:
                choices = [c.strip() for c in choice.split(",")]
                for c in choices:
                    if c in LANGUAGE_MAPPING:
                        selected_langs.append(LANGUAGE_MAPPING[c])
                    else:
                        print(f"⚠️  Pilihan bahasa '{c}' tidak valid, dilewati.")
        except EOFError:
            selected_langs = [LANGUAGE_MAPPING["1"]]

    # Step 3: Get template path
    try:
        template_base = _get_template_path()
    except Exception as e:
        print(f"❌ Error internal: {e}")
        sys.exit(1)
        return
        
    current_work_dir = Path.cwd()

    if not (current_work_dir / ".git").exists():
        print("⚠️  Direktori .git tidak ditemukan. Pastikan Anda menjalankan ini di root repository.")

    # Step 4: Sync Process
    for tool in selected_tools:
        tool_name = tool["name"]
        print(f"\n📦 Memproses konfigurasi untuk {tool_name}...")
        
        for folder_name in tool["folders"]:
            dest_root = current_work_dir / folder_name
            dest_skills = dest_root / "skills"
            
            # A. Sync Base (Rules & Workflows)
            source_base = template_base / folder_name
            _sync_template_folder(source_base, dest_root, args.verbose)
            
            # B. Sync Core Skills
            source_core = template_base / "core"
            _sync_template_folder(source_core, dest_skills, args.verbose)
            
            # C. Sync Language Skills
            for lang in selected_langs:
                source_lang = template_base / "languages" / lang["id"]
                _sync_template_folder(source_lang, dest_skills, args.verbose)
                
            # D. Sync Domain Skills (All for now)
            source_domains = template_base / "domains"
            _sync_template_folder(source_domains, dest_skills, args.verbose)

        # E. Handle Standalone Files
        try:
            core_block_path = template_base / "standalone" / "core-rules-block.md"
            if core_block_path.exists():
                template_block = core_block_path.read_text(encoding="utf-8")
                for file_name in tool["files"]:
                    target_path = current_work_dir / file_name
                    _update_standalone_file(target_path, template_block)
        except Exception as e:
            print(f"❌ Gagal memproses file standalone untuk {tool_name}: {e}")

    print("\n✨ Berhasil! Konfigurasi untuk tool dan bahasa terpilih telah disiapkan.")


if __name__ == "__main__":
    run()
