
import os
import re
import argparse
import subprocess


def add_tag_to_tagged_decorator(content, tag_to_add):
    """Añade el tag al decorador @tagged existente, manejando multi-línea."""
    # Patrón que captura @tagged(...) incluyendo contenido multi-línea
    pattern = r'(@tagged\()([^)]*?)(\))'

    def replace_tagged(match):
        prefix = match.group(1)  # @tagged(
        args = match.group(2)    # contenido interno
        suffix = match.group(3)  # )

        # Verificar si el tag ya existe
        if f'"{tag_to_add}"' in args or f"'{tag_to_add}'" in args:
            return match.group(0)  # Sin cambios

        # Añadir el tag al final
        args = args.rstrip()
        if args:
            args = f'{args}, "{tag_to_add}"'
        else:
            args = f'"{tag_to_add}"'

        return f'{prefix}{args}{suffix}'

    return re.sub(pattern, replace_tagged, content, flags=re.DOTALL)


def add_tagged_import(content):
    """Añade 'tagged' al import de odoo.tests.common si no existe."""
    if "tagged" in content:
        return content

    # Buscar el patrón de import
    pattern = r'(from odoo\.tests\.common import\s+)([^\n]+)'

    def add_import(match):
        prefix = match.group(1)
        imports = match.group(2)
        return f'{prefix}tagged, {imports}'

    return re.sub(pattern, add_import, content)


def add_tagged_decorator_to_classes(content, tag_to_add):
    """Añade @tagged a clases de test que no lo tienen, preservando indentación."""
    lines = content.split('\n')
    new_lines = []
    i = 0
    changed = False

    while i < len(lines):
        line = lines[i]
        # Detectar si es una definición de clase Test
        class_match = re.match(r'^(\s*)(class\s+Test\w*\s*\()', line)

        if class_match:
            indent = class_match.group(1)
            # Verificar si la línea anterior ya tiene @tagged
            has_tagged = False
            if new_lines:
                # Buscar hacia atrás por decoradores
                for j in range(len(new_lines) - 1, -1, -1):
                    prev_line = new_lines[j].strip()
                    if prev_line.startswith('@tagged'):
                        has_tagged = True
                        break
                    elif prev_line.startswith('@') or prev_line == '':
                        continue  # Otros decoradores o líneas vacías
                    else:
                        break  # Encontramos código que no es decorador

            if not has_tagged:
                new_lines.append(f'{indent}@tagged("{tag_to_add}")')
                changed = True

        new_lines.append(line)
        i += 1

    return '\n'.join(new_lines), changed


def tag_tests(base_path, tag_to_add="initium", exclude_dirs=None):
    if exclude_dirs is None:
        exclude_dirs = ["extra", "pending_initium_20", ".git", "__pycache__", "docs", "media"]

    print(f"Buscando archivos de test en {base_path}...")

    updated_count = 0
    for root, dirs, files in os.walk(base_path):
        # Filtrar directorios excluidos
        dirs[:] = [d for d in dirs if d not in exclude_dirs]

        # Odoo standard: tests are in a 'tests' directory
        if "tests" in root.split(os.sep):
            for file in files:
                if file.endswith(".py") and file != "__init__.py":
                    file_path = os.path.join(root, file)
                    with open(file_path, "r", encoding="utf-8") as f:
                        content = f.read()

                    original_content = content

                    if "@tagged(" in content:
                        # Si ya tiene @tagged, añadir tag si no está
                        content = add_tag_to_tagged_decorator(content, tag_to_add)
                    else:
                        # Si no tiene @tagged, añadir import y decorador
                        content = add_tagged_import(content)
                        content, _ = add_tagged_decorator_to_classes(content, tag_to_add)

                    if content != original_content:
                        with open(file_path, "w", encoding="utf-8") as f:
                            f.write(content)
                        print(f"✅ Etiqueta añadida a: {file_path}")
                        updated_count += 1

    print(f"Proceso finalizado. {updated_count} archivos actualizados.")

def main():
    parser = argparse.ArgumentParser(description="Añade automáticamente etiquetas de test a módulos Odoo.")
    group = parser.add_mutually_exclusive_group()
    group.add_argument("--all", action="store_true", help="Procesar todo el repositorio (global)")
    group.add_argument("--path", "-p", help="Procesar un directorio específico")
    
    parser.add_argument("--tag", default="initium", help="Etiqueta a añadir (default: initium)")
    
    args = parser.parse_args()

    # Determine base directory
    if args.all:
        try:
            root = subprocess.run(["git", "rev-parse", "--show-toplevel"], 
                               capture_output=True, text=True, check=True).stdout.strip()
            directory = root
        except:
            directory = os.getcwd()
        print(f"Modo GLOBAL: Procesando desde {directory}")
    elif args.path:
        directory = os.path.abspath(args.path)
        print(f"Modo DIRECTORIO: Procesando {directory}")
    else:
        directory = os.getcwd()
        print(f"Modo LOCAL: Procesando directorio actual {directory}")

    if not os.path.exists(directory):
        print(f"Error: La ruta no existe: {directory}")
        return

    tag_tests(directory, tag_to_add=args.tag)

if __name__ == "__main__":
    main()
