"""Export skills as shareable archives and optionally publish to GitHub Gist."""

from __future__ import annotations

import json
import os
import shutil
import tarfile
from dataclasses import dataclass
from io import BytesIO
from pathlib import Path
from typing import Any


@dataclass
class ExportResult:
    """Result of a skill export."""

    archive_path: Path
    skill_name: str
    install_command: str
    gist_url: str | None = None


def export_skill(
    skill_name: str,
    *,
    output_dir: Path | None = None,
    skills_dir: Path | None = None,
    create_gist: bool = False,
) -> ExportResult:
    """Export a skill directory as a .tar.gz archive.

    Args:
        skill_name: Name of the skill to export.
        output_dir: Directory to write the archive. Defaults to cwd.
        skills_dir: Override skills directory for testing.
        create_gist: If True, upload to GitHub Gist (requires GITHUB_TOKEN).

    Returns:
        ExportResult with archive path and install command.

    Raises:
        FileNotFoundError: If the skill doesn't exist.
        ValueError: If skill directory is missing required files.
    """
    from alive.config import SKILLS_DIR

    skills_dir = skills_dir or SKILLS_DIR
    skill_dir = skills_dir / skill_name

    if not skill_dir.exists():
        raise FileNotFoundError(f"Skill '{skill_name}' not found in {skills_dir}")

    # Validate required files
    _validate_skill_dir(skill_dir, skill_name)

    # Build archive
    output_dir = output_dir or Path.cwd()
    archive_name = f"{skill_name}.alive-skill.tar.gz"
    archive_path = output_dir / archive_name

    with tarfile.open(archive_path, "w:gz") as tar:
        tar.add(str(skill_dir), arcname=skill_name)

    install_cmd = f"alive install {archive_name}"

    # Optionally publish to gist
    gist_url = None
    if create_gist:
        gist_url = _create_gist(skill_dir, skill_name)
        if gist_url:
            install_cmd = f"alive install {gist_url}"

    return ExportResult(
        archive_path=archive_path,
        skill_name=skill_name,
        install_command=install_cmd,
        gist_url=gist_url,
    )


def _validate_skill_dir(skill_dir: Path, skill_name: str) -> None:
    """Ensure a skill directory has required files."""
    required = ["skill.py", "metadata.json"]
    missing = [f for f in required if not (skill_dir / f).exists()]
    if missing:
        raise ValueError(
            f"Skill '{skill_name}' is missing required files: {', '.join(missing)}"
        )


def _create_gist(skill_dir: Path, skill_name: str) -> str | None:
    """Upload skill files to a GitHub Gist. Returns the gist URL or None."""
    import urllib.request
    import urllib.error

    token = os.environ.get("GITHUB_TOKEN")
    if not token:
        return None

    # Collect files for gist
    files: dict[str, dict[str, str]] = {}
    for path in sorted(skill_dir.iterdir()):
        if path.is_file() and not path.name.startswith("."):
            try:
                content = path.read_text()
                files[path.name] = {"content": content}
            except UnicodeDecodeError:
                continue  # skip binary files

    if not files:
        return None

    # Load description from metadata
    meta_path = skill_dir / "metadata.json"
    description = f"Alive skill: {skill_name}"
    if meta_path.exists():
        try:
            meta = json.loads(meta_path.read_text())
            description = f"Alive skill: {skill_name} — {meta.get('description', '')}"
        except (json.JSONDecodeError, KeyError):
            pass

    payload = json.dumps({
        "description": description,
        "public": True,
        "files": files,
    }).encode()

    req = urllib.request.Request(
        "https://api.github.com/gists",
        data=payload,
        headers={
            "Authorization": f"Bearer {token}",
            "Accept": "application/vnd.github+json",
            "Content-Type": "application/json",
        },
    )

    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            data = json.loads(resp.read())
            return data.get("html_url")
    except (urllib.error.URLError, json.JSONDecodeError, KeyError):
        return None
