# nova_cli\local\file_manager\commands.py
import os
import re
from typing import Optional
import shlex
import subprocess

from nova_cli.local.ui import ui
import core.prompts as prompts  # keep as-is for now
from nova_cli.local.utils import parse_multiple_files

from nova_cli.local.file_manager.io_ops import safe_delete, safe_write
from nova_cli.local.file_manager.edit_ops import apply_surgical_edit
from nova_cli.local.file_manager.path_ops import validate_path


IGNORE_DIRS = {"path", "folder", "directory", "filename", "your_path", "project_name"}


def _normalize_text(s: str) -> str:
    if s is None:
        return ""
    s = s.replace("\r\n", "\n").replace("\r", "\n")
    s = s.lstrip("\ufeff")  # remove BOM if present
    return s


def _strip_code_fences(s: str) -> str:
    """
    Cleans content by removing Markdown code fences (```python ... ```).
    Handles cases where AI double-wraps or includes language identifiers.
    """
    s = _normalize_text(s).strip()
    
    # 1. Broad cleanup: Remove any leading/trailing triple backticks + language tags
    # This regex looks for ``` followed by optional word characters, then a newline
    # at the very start, and matching backticks at the very end.
    s = re.sub(r"^```[a-zA-Z0-9_+\-]*\s*\n?", "", s)
    s = re.sub(r"\n?```$", "", s)
    
    return s.strip()



def is_placeholder_path(path: str) -> bool:
    """Detects documentation placeholders to avoid executing help examples."""
    path_lower = path.lower().replace("\\", "/")
    if path_lower in ["example.py", "file.ext", "path/to/target", "path/to/dir", "path/to/file.ext"]:
        return True
    if "path/to/" in path_lower:
        return True
    return False


def handle_ai_commands(text: str, errors: Optional[list[str]] = None, cwd: Optional[str] = None) -> list[str]:
    """
    Parses and executes AI commands ([MKDIR], [DELETE], [EDIT], [CREATE], [SHELL]).
    Returns a list of file paths that were modified.
    """
    modified_files: list[str] = []
    errors = errors or []

    # 1) MKDIR
    mkdir_matches = re.findall(r"(?:\*\*|__)?\[MKDIR:\s*(.*?)\s*\](?:\*\*|__)?", text, re.IGNORECASE)
    folder_created = False

    for folder in mkdir_matches:
        try:
            folder = folder.strip()
            if not folder:
                continue
            if folder.lower() in IGNORE_DIRS:
                continue
            if is_placeholder_path(folder):
                continue

            full_path = validate_path(folder)
            os.makedirs(full_path, exist_ok=True)
            ui.print(f"[bold green]>> Created Directory: {folder}[/bold green]")
            folder_created = True

        except PermissionError as e:
            ui.print(f"[bold red]{e}[/bold red]")
        except Exception as e:
            ui.print(f"[red]>> Failed to create directory {folder}: {e}[/red]")

    if folder_created:
        prompts.clear_file_tree_cache()

    # 2) DELETE
    delete_matches = re.findall(r"(?:\*\*|__)?\[DELETE:\s*(.*?)\s*\](?:\*\*|__)?", text, re.IGNORECASE)
    for target in delete_matches:
        target = target.strip()
        if is_placeholder_path(target):
            continue
        safe_delete(target)

    # 3) EDIT
    edit_split_pattern = r"(?:\*\*|__)?\[EDIT:\s*(.*?)\s*\](?:\*\*|__)?"
    edit_segments = re.split(edit_split_pattern, text, flags=re.IGNORECASE)

    if len(edit_segments) >= 3:
        for i in range(1, len(edit_segments), 2):
            filename = edit_segments[i].strip().replace('"', "").replace("'", "").replace("\\", "/")
            
            if cwd and not os.path.isabs(filename):
                filename = os.path.abspath(os.path.join(cwd, filename))
            
            if is_placeholder_path(filename):
                continue

            following_text = edit_segments[i + 1]

            block_pattern = r"<{4,10}(?:\s*SEARCH)?\s*\n?(.*?)\n?={4,10}\s*\n?(.*?)\n?>{4,10}(?:\s*REPLACE)?"
            blocks = re.findall(block_pattern, following_text, re.DOTALL)

            if not blocks:
                ui.print(f"[yellow]>> [EDIT:{filename}] called but no valid SEARCH/REPLACE blocks found.[/yellow]")
                errors.append(f"EDIT_FAILED_NO_BLOCKS file={filename}")
                continue

            edits_made = False

            for search_block, replace_block in blocks:
                # CRITICAL FIX: strip ``` fences + normalize before matching/writing
                search_clean = _strip_code_fences(search_block)
                replace_clean = _strip_code_fences(replace_block)

                # Also normalize to avoid newline/BOM mismatch issues
                search_clean = _normalize_text(search_clean)
                replace_clean = _normalize_text(replace_clean)

                if apply_surgical_edit(filename, search_clean, replace_clean):
                    edits_made = True
                    modified_files.append(filename)

            if edits_made:
                prompts.clear_file_tree_cache()
                pass

    # 4) CREATE
    files_to_create = parse_multiple_files(text)

    if files_to_create:
        for filename, code in files_to_create:
            if cwd and not os.path.isabs(filename):
                filename = os.path.abspath(os.path.join(cwd, filename))
            if is_placeholder_path(filename):
                continue

            # CRITICAL: Strip any code fences that the AI might have nested
            code = _strip_code_fences(code)

            if safe_write(filename, code):
                modified_files.append(filename)
                prompts.clear_file_tree_cache()
    else:
        if "[CREATE:" in text and "[EDIT:" not in text:
            if not any(is_placeholder_path(m) for m in re.findall(r"\[CREATE:\s*(.*?)\s*\]", text)):
                ui.print("[yellow]>> Commands found but parsing failed. Ensure code blocks follow [CREATE] tags.[/yellow]")
                errors.append("CREATE_FAILED_PARSE_MULTIFILE")

    # 5) SHELL (Dependency Fixer)
    shell_matches = re.findall(r"\[SHELL:\s*(.*?)\s*\]", text, re.IGNORECASE)
    for shell_cmd in shell_matches:
        shell_cmd = shell_cmd.strip()
        if shell_cmd.lower().startswith("pip install"):
            try:
                ui.print(f"[bold cyan]>> Auto-Installing Dependency: {shell_cmd}[/bold cyan]", soft_wrap=True)
                subprocess.check_call(shlex.split(shell_cmd))
                ui.print("[bold green]>> Installation successful.[/bold green]", soft_wrap=True)
                modified_files.append("SYSTEM_ENVIRONMENT")
            except Exception as e:
                ui.print(f"[red]>> Installation failed: {e}[/red]", soft_wrap=True)
                errors.append(f"SHELL_INSTALL_FAILED err={str(e)}")
        else:
            ui.print("[red]>> Blocked: Only 'pip install' commands are permitted.[/red]", soft_wrap=True)
            errors.append(f"SHELL_BLOCKED cmd={shell_cmd}")
    return modified_files
