import contextlib
import shutil
from collections.abc import Collection
from pathlib import Path
from uuid import uuid4

from .render import render_skill_markdown, render_skill_script
from .types import CreatedSkill, SkillSpec


def write_text_file(path: Path, content: str) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(content.rstrip("\n") + "\n", encoding="utf-8", newline="\n")


def persist_skill(
    skills_directory: Path,
    skill_spec: SkillSpec,
    *,
    existing_skill_names: Collection[str] = (),
) -> CreatedSkill:
    existing_names = {name.casefold() for name in existing_skill_names}
    if skill_spec.name.casefold() in existing_names:
        raise FileExistsError(f"Já existe uma skill chamada '{skill_spec.name}'.")

    skills_directory.mkdir(parents=True, exist_ok=True)
    target_dir = skills_directory / skill_spec.name
    if target_dir.exists():
        raise FileExistsError(f"O diretório '{skill_spec.name}' já existe em {skills_directory}.")

    temp_dir = skills_directory / f".{skill_spec.name}.tmp-{uuid4().hex}"
    temp_dir.mkdir()
    created_files: list[str] = []

    try:
        skill_md = render_skill_markdown(
            name=skill_spec.name,
            description=skill_spec.description,
            instructions=skill_spec.instructions,
            scripts=skill_spec.scripts,
        )

        write_text_file(temp_dir / "SKILL.md", skill_md)
        created_files.append("SKILL.md")

        for script in skill_spec.scripts:
            write_text_file(temp_dir / "scripts" / script.file_name, render_skill_script(script))
            created_files.append(f"scripts/{script.file_name}")

        write_text_file(
            temp_dir / "meta.json",
            skill_spec.model_dump_json(indent=2, ensure_ascii=False),
        )

        temp_dir.replace(target_dir)

    except Exception:
        with contextlib.suppress(OSError):
            shutil.rmtree(temp_dir)
        raise

    return CreatedSkill(
        name=skill_spec.name,
        skill_directory=target_dir,
        created_files=created_files,
    )


def update_skill(skills_directory: Path, skill_spec: SkillSpec) -> CreatedSkill:
    target_dir = skills_directory / skill_spec.name
    backup_dir = skills_directory / f".{skill_spec.name}.backup-{uuid4().hex}"

    target_dir.rename(backup_dir)
    try:
        result = persist_skill(skills_directory, skill_spec)
        shutil.rmtree(backup_dir)
        return result
    except Exception:
        backup_dir.rename(target_dir)
        raise
