#!/usr/bin/env python3
"""
Generate a new SophClaw skill skeleton.

Receives structured parameters from the LLM (no interactive Q&A) and
creates the full directory tree with skill.json, SKILL.md template,
pyproject.toml, and optional resource directories.
"""

import argparse
import json
import re
import sys
from datetime import date
from pathlib import Path

MAX_SKILL_NAME_LENGTH = 64
VALID_TYPES = {"builtin", "store", "private", "tmp"}
ALLOWED_RESOURCES = {"scripts", "references", "assets"}

SKILL_JSON_TEMPLATE = """{{
  "name": "{skill_name}",
  "version": "1.0.0",
  "types": [{types}],
  "displayName": "{display_name}",
  "description": "{skill_description}",
  "changelog": [
    {{
      "version": "1.0.0",
      "date": "{today}",
      "changes": ["初次提交"]
    }}
  ],
  "createdAt": "{today}",
  "updatedAt": "{today}"
}}
"""

PYPROJECT_TEMPLATE = """[project]
name = "{skill_name}"
version = "1.0.0"
description = "{description}"
requires-python = ">=3.8"
"""

SKILL_MD_TEMPLATE = """---
name: {skill_name}
description: [TODO: 功能 + 触发场景。一句话说明做什么 + 何时触发，例如"压缩图片。当用户要求压缩图片、减小图片体积时使用。"]
---

# {skill_title}

[TODO: 简要描述 skill 功能]

## 用法

[TODO: 给出调用命令示例，使用 uv run，路径不含 src/]

```bash
uv run {{baseDir}}/scripts/xxx.py --arg value
```

## 输出格式

[TODO: 描述输出格式，便于 LLM 解析]
- STATUS: succeeded / failed
- OUTPUT: ...

## 注意事项

[TODO: 限制条件、边界情况、常见错误]
"""


def normalize_skill_name(raw_name):
    """Normalize to lowercase kebab-case."""
    name = raw_name.strip().lower()
    name = re.sub(r"[^a-z0-9]+", "-", name)
    name = name.strip("-")
    name = re.sub(r"-{2,}", "-", name)
    return name


def title_case_skill_name(name):
    """Convert hyphenated name to Title Case."""
    return " ".join(word.capitalize() for word in name.split("-"))


def validate_name(name):
    """Validate skill name format. Returns (valid, error_message)."""
    if not name:
        return False, "Skill name must include at least one letter or digit."
    if len(name) > MAX_SKILL_NAME_LENGTH:
        return False, "Skill name '{}' is too long ({} chars, max {}).".format(
            name, len(name), MAX_SKILL_NAME_LENGTH
        )
    if not re.match(r"^[a-z0-9-]+$", name):
        return False, "Skill name must be kebab-case (lowercase letters, digits, hyphens)."
    return True, ""


def validate_type(skill_type):
    """Validate type value. Returns (valid, error_message)."""
    if skill_type not in VALID_TYPES:
        return False, "Invalid type '{}'. Must be one of: {}.".format(
            skill_type, ", ".join(sorted(VALID_TYPES))
        )
    return True, ""


def parse_resources(raw_resources):
    """Parse comma-separated resource list. Returns (list, error_message)."""
    if not raw_resources:
        return [], ""
    resources = [r.strip() for r in raw_resources.split(",") if r.strip()]
    invalid = sorted(set(r for r in resources if r not in ALLOWED_RESOURCES))
    if invalid:
        return [], "Unknown resource type(s): {}. Allowed: {}.".format(
            ", ".join(invalid), ", ".join(sorted(ALLOWED_RESOURCES))
        )
    deduped = []
    seen = set()
    for r in resources:
        if r not in seen:
            deduped.append(r)
            seen.add(r)
    return deduped, ""


def generate_skill(skill_name, skill_type, display_name, skill_description, resources, output_dir=None):
    """Create the full skill directory structure."""
    today = date.today().isoformat()
    skill_title = title_case_skill_name(skill_name)

    base = Path(output_dir) if output_dir else Path.cwd() / "skills"
    skill_dir = base / skill_name
    src_dir = skill_dir / "src"

    # Check for existing directory
    if skill_dir.exists():
        print("STATUS=failed")
        print("ERROR_MESSAGE=Skill directory already exists: {}".format(skill_dir))
        return False

    created_files = []

    # Create directories
    skill_dir.mkdir(parents=True, exist_ok=False)
    src_dir.mkdir(parents=True, exist_ok=False)

    # Generate skill.json
    types_str = '"{}"'.format(skill_type)
    skill_json_content = SKILL_JSON_TEMPLATE.format(
        skill_name=skill_name,
        types=types_str,
        display_name=display_name,
        skill_description=skill_description,
        today=today,
    )
    skill_json_path = skill_dir / "skill.json"
    skill_json_path.write_text(skill_json_content, encoding="utf-8")
    created_files.append(str(skill_json_path))

    # Generate SKILL.md template
    skill_md_content = SKILL_MD_TEMPLATE.format(
        skill_name=skill_name,
        skill_title=skill_title,
    )
    skill_md_path = src_dir / "SKILL.md"
    skill_md_path.write_text(skill_md_content, encoding="utf-8")
    created_files.append(str(skill_md_path))

    # Generate pyproject.toml
    pyproject_content = PYPROJECT_TEMPLATE.format(
        skill_name=skill_name,
        description=skill_description if skill_description else skill_name,
    )
    pyproject_path = src_dir / "pyproject.toml"
    pyproject_path.write_text(pyproject_content, encoding="utf-8")
    created_files.append(str(pyproject_path))

    # Create resource directories
    for resource in resources:
        resource_dir = src_dir / resource
        resource_dir.mkdir(exist_ok=True)
        created_files.append("{}/".format(resource_dir))
        if resource == "scripts":
            init_path = resource_dir / "__init__.py"
            init_path.write_text("# {}\n".format(skill_name), encoding="utf-8")
            created_files.append(str(init_path))

    # Output
    print("STATUS=succeeded")
    print("SKILL_DIR={}".format(skill_dir))
    print("SKILL_NAME={}".format(skill_name))
    print("SKILL_TYPE={}".format(skill_type))
    print("CREATED_FILES={}".format(",".join(created_files)))
    return True


def main():
    parser = argparse.ArgumentParser(
        description="Generate a new SophClaw skill skeleton."
    )
    parser.add_argument("--name", required=True, help="Skill name (kebab-case)")
    parser.add_argument(
        "--type", required=True, dest="skill_type",
        help="Skill type: builtin, store, private, or tmp"
    )
    parser.add_argument("--display-name", default="", help="Chinese display name (required for store)")
    parser.add_argument("--skill-description", default="", help="Chinese description (required for store)")
    parser.add_argument("--resources", default="", help="Comma-separated: scripts,references,assets")
    parser.add_argument("--output-dir", default="", help="Output directory for the skill (defaults to ./skills/)")
    args = parser.parse_args()

    # Validate name
    skill_name = normalize_skill_name(args.name)
    if skill_name != args.name:
        print("Note: Normalized skill name from '{}' to '{}'.".format(args.name, skill_name))
    valid, error = validate_name(skill_name)
    if not valid:
        print("STATUS=failed")
        print("ERROR_MESSAGE={}".format(error))
        sys.exit(1)

    # Validate type
    valid, error = validate_type(args.skill_type)
    if not valid:
        print("STATUS=failed")
        print("ERROR_MESSAGE={}".format(error))
        sys.exit(1)

    # Validate store requirements
    if args.skill_type == "store":
        if not args.display_name.strip():
            print("STATUS=failed")
            print("ERROR_MESSAGE=store type requires --display-name (Chinese display name)")
            sys.exit(1)
        if not args.skill_description.strip():
            print("STATUS=failed")
            print("ERROR_MESSAGE=store type requires --skill-description (Chinese description)")
            sys.exit(1)

    # Parse resources
    resources, error = parse_resources(args.resources)
    if error:
        print("STATUS=failed")
        print("ERROR_MESSAGE={}".format(error))
        sys.exit(1)

    success = generate_skill(
        skill_name=skill_name,
        skill_type=args.skill_type,
        display_name=args.display_name.strip(),
        skill_description=args.skill_description.strip(),
        resources=resources,
        output_dir=args.output_dir.strip() or None,
    )

    if not success:
        sys.exit(1)


if __name__ == "__main__":
    main()