"""Service for generating and saving new programming challenges via LLM backend."""
import os
import re
import httpx
from typing import Dict, Any
from src.core.config import config
from src.core.mentor import get_chat_completions_url

SYSTEM_PROMPT_GENERATOR = """You are a Master Software Engineering Challenge Creator for TactiTerm.
Your task is to generate a complete, high-quality coding challenge formatted strictly as a Markdown document according to the specification below.

### STRICT MARKDOWN FORMAT SPECIFICATION:
```markdown
# Challenge: <Short Clear Title>
**Difficulty:** <Easy|Medium|Hard|Advanced>
**Language:** <Python|C#|C++|Java|JavaScript|TypeScript|Rust|Lua|HTML|Go>
**Subject:** <Specific Subject/Topic>

## Description
<Clear multi-paragraph explanation of the problem, background context, and what the student needs to build.>

## Requirements
- <Clear, objective requirement 1>
- <Clear, objective requirement 2>
- <Clear, objective requirement 3>

## Hints
- <Helpful conceptual hint 1>
- <Helpful conceptual hint 2>

## Validation
- **Check:** <Validation command or test description>
- **Expected Output:** <Expected output or return value>
```

### RULES:
1. ONLY return the valid Markdown content starting with `# Challenge: `.
2. Do NOT enclose the entire Markdown output in outer markdown triple backticks.
3. Ensure the Language is one of: Python, C#, C++, Java, JavaScript, TypeScript, Rust, Lua, HTML, Go.
4. Ensure Difficulty is one of: Easy, Medium, Hard, Advanced.
5. Create realistic, engaging, and pedagogically sound requirements and hints.
"""


class ChallengeGenerator:
    """Generates new challenge markdown files using the configured LLM backend."""

    def __init__(self, challenges_dir: str = "src/challenges/"):
        self.challenges_dir = challenges_dir

    async def generate_challenge_async(
        self, prompt_text: str, difficulty: str = "Medium", language: str = "Python", subject: str = "General"
    ) -> Dict[str, Any]:
        endpoint = get_chat_completions_url(config.llm_base_url)

        user_content = (
            f"Generate a {difficulty} difficulty challenge in {language} focusing on the subject '{subject}'.\n"
            f"User Prompt Details: {prompt_text}"
        )

        payload = {
            "model": config.llm_model,
            "messages": [
                {"role": "system", "content": SYSTEM_PROMPT_GENERATOR},
                {"role": "user", "content": user_content},
            ],
            "temperature": 0.7,
            "max_tokens": config.llm_max_tokens,
        }

        headers = {"Content-Type": "application/json"}
        if config.llm_api_key and config.llm_api_key != "not-needed":
            headers["Authorization"] = f"Bearer {config.llm_api_key}"

        try:
            async with httpx.AsyncClient(timeout=config.llm_timeout, follow_redirects=True) as client:
                response = await client.post(endpoint, json=payload, headers=headers)
                response.raise_for_status()
                data = response.json()

                raw_md = (
                    data.get("choices", [{}])[0]
                    .get("message", {})
                    .get("content", "")
                    .strip()
                )

                # Clean up outer markdown wrapper if present
                if raw_md.startswith("```markdown"):
                    raw_md = raw_md.replace("```markdown", "", 1).rstrip("` \n")
                elif raw_md.startswith("```"):
                    raw_md = raw_md.replace("```", "", 1).rstrip("` \n")

                if raw_md:
                    # Generate filename slug from title
                    title_match = re.search(r"# Challenge: (.*)", raw_md)
                    title = title_match.group(1).strip() if title_match else "new-challenge"
                    slug = re.sub(r"[^\w\s-]", "", title.lower()).strip().replace(" ", "-")
                    filename = f"{slug}.md"

                    return {
                        "status": "success",
                        "filename": filename,
                        "markdown": raw_md,
                        "title": title,
                    }
                else:
                    return {
                        "status": "error",
                        "message": "Received empty response from LLM server.",
                    }
        except Exception as e:
            return {
                "status": "error",
                "message": f"Failed to generate challenge via LLM: {e}",
            }

    def save_challenge(self, filename: str, markdown_content: str) -> Dict[str, Any]:
        """Save a generated markdown challenge file into src/challenges/."""
        if not filename.endswith(".md"):
            filename = f"{filename}.md"

        # Sanitize filename
        safe_filename = os.path.basename(filename)
        save_path = os.path.join(self.challenges_dir, safe_filename)

        os.makedirs(self.challenges_dir, exist_ok=True)
        try:
            with open(save_path, "w", encoding="utf-8") as f:
                f.write(markdown_content)
            return {
                "status": "success",
                "path": save_path,
                "filename": safe_filename,
            }
        except Exception as e:
            return {
                "status": "error",
                "message": f"Failed to save challenge to {save_path}: {e}",
            }


generator = ChallengeGenerator()
