from __future__ import annotations

import json
import logging
import re
from pathlib import Path
from typing import Annotated

from fastapi import APIRouter, Depends, HTTPException, Request

from codeflash_api.auth._deps import (
    check_rate_limit,
    require_auth,
    track_usage,
)
from codeflash_api.auth.models import AuthenticatedUser  # noqa: TC001
from codeflash_api.llm._models import EXECUTE_MODEL
from codeflash_api.workflow.schemas import (
    WorkflowGenErrorResponse,
    WorkflowGenRequest,
    WorkflowGenResponse,
)

log = logging.getLogger(__name__)

router = APIRouter()

_PROMPTS_DIR = Path(__file__).parent / "prompts"
SYSTEM_PROMPT = (_PROMPTS_DIR / "system_prompt.md").read_text()
USER_PROMPT = (_PROMPTS_DIR / "user_prompt.md").read_text()

_steps_section_re = re.compile(r"steps:\s*\n((?:[^\n]+\n)*)", re.MULTILINE)
_array_match_re = re.compile(r"(- name:.*?)(?=\n\n|\Z)", re.DOTALL)
_yaml_like_re = re.compile(r"(- name:.*)", re.DOTALL)


def _extract_yaml_steps(text: str) -> str | None:
    """
    Extract YAML steps section from LLM response text.
    """
    steps_match = _steps_section_re.search(text)
    if steps_match:
        steps_content = steps_match.group(1)
        formatted_lines: list[str] = []
        for line in steps_content.split("\n"):
            stripped_line = line.strip()
            if not stripped_line:
                continue
            if line.startswith("-"):
                formatted_lines.append(line)
            elif stripped_line.startswith("-"):
                formatted_lines.append("  " + stripped_line)
            else:
                formatted_lines.append(line)
        return "steps:\n" + "\n".join(formatted_lines)

    array_match = _array_match_re.search(text)
    if array_match:
        return "steps:\n" + array_match.group(1)

    yaml_match = _yaml_like_re.search(text)
    if yaml_match:
        return "steps:\n" + yaml_match.group(1)

    return None


@router.post(
    "/ai/workflow-gen",
    response_model=WorkflowGenResponse,
    responses={
        400: {"model": WorkflowGenErrorResponse},
        500: {"model": WorkflowGenErrorResponse},
    },
)
async def generate_workflow_steps(
    request: Request,
    data: WorkflowGenRequest,
    user: Annotated[AuthenticatedUser, Depends(require_auth)],
    _rate: Annotated[None, Depends(check_rate_limit)],
    _usage: Annotated[None, Depends(track_usage)],
) -> WorkflowGenResponse:
    """
    Generate GitHub Actions workflow steps from repository analysis.
    """
    if not data.repo_files and not data.directory_structure:
        raise HTTPException(
            status_code=400,
            detail=(
                "At least one of repo_files or"
                " directory_structure must be provided"
            ),
        )

    files_text = "\n".join(
        f"**{path}:**\n{content[:8000]}\n"
        for path, content in data.repo_files.items()
    )
    structure_text = json.dumps(data.directory_structure, indent=2)
    config_text = (
        json.dumps(data.codeflash_config, indent=2)
        if data.codeflash_config
        else "Not available"
    )

    user_prompt = USER_PROMPT.format(
        repo_files=files_text,
        directory_structure=structure_text,
        codeflash_config=config_text,
    )

    llm_client = request.app.state.llm_client

    try:
        response = await llm_client.call(
            llm=EXECUTE_MODEL,
            messages=[
                {"role": "system", "content": SYSTEM_PROMPT},
                {"role": "user", "content": user_prompt},
            ],
            call_type="workflow_generation",
            trace_id=data.trace_id,
        )
    except Exception:
        log.exception("LLM call failed: trace_id=%s", data.trace_id)
        raise HTTPException(
            status_code=500,
            detail=("Failed to generate workflow steps. Please try again."),
        ) from None

    if not response.content:
        log.warning(
            "LLM returned empty response: trace_id=%s",
            data.trace_id,
        )
        raise HTTPException(
            status_code=500,
            detail=(
                "Failed to generate workflow steps."
                " Please try again or use the static"
                " template."
            ),
        )

    steps_yaml = _extract_yaml_steps(response.content.strip())
    if not steps_yaml:
        log.warning(
            "Could not extract YAML steps: trace_id=%s response=%.200s",
            data.trace_id,
            response.content,
        )
        raise HTTPException(
            status_code=500,
            detail=(
                "Failed to generate workflow steps."
                " Please try again or use the static"
                " template."
            ),
        )

    log.info(
        "Generated workflow steps: trace_id=%s len=%d",
        data.trace_id,
        len(steps_yaml),
    )
    return WorkflowGenResponse(workflow_steps=steps_yaml)
