import requests
import json
import re
import os
from .config import config
from .detector import Stack
from .providers import PROVIDERS_CONFIG
from .utils import get_logger

logger = get_logger("generator")

def generate_pipeline(stack: Stack, api_key: str, provider_key: str = None) -> str:
    """Generates a strictly verified and highly compatible CI/CD pipeline."""
    
    provider_info = PROVIDERS_CONFIG.get(provider_key, list(PROVIDERS_CONFIG.values())[0])
    url = provider_info["url"].rstrip("/") + "/chat/completions"
    model = api_key if provider_key == "OLLAMA_MODEL" else provider_info["model"]
    
    headers = {"Content-Type": "application/json"}
    if provider_key != "OLLAMA_MODEL":
        headers["Authorization"] = f"Bearer {api_key}"

    lang = stack.language.lower() if stack.language else "python"
    
    # Determine Snyk Action
    snyk_action = ""
    if "python" in lang: snyk_action = "python"
    elif "c#" in lang or "net" in lang: snyk_action = "dotnet"
    elif "node" in lang: snyk_action = "node"

    # Get commands from AI
    prompt = f"Act as a CI console. Provide ONLY the shell commands for a {stack.language} project to build and test. DO NOT EXPLAIN. NO MARKDOWN. NO YAML."
    data = {"model": model, "messages": [{"role": "user", "content": prompt}], "temperature": 0.0}
    
    valid_commands = []
    try:
        response = requests.post(url, headers=headers, data=json.dumps(data), timeout=300)
        response.raise_for_status()
        raw_output = response.json()['choices'][0]['message']['content'].strip()
        lines = re.sub(r"```[\w]*\n?", "", raw_output).replace("```", "").split("\n")
        
        if "bash" in lang:
            valid_commands.append("chmod +x *.sh")

        for line in lines:
            t = line.strip()
            if not t or not any(t.startswith(c) for c in ["dotnet", "npm", "pip", "pytest", "python", "cd ", "mkdir ", "ls ", "bash ", "chmod ", "./"]):
                continue
            if any(x in t for x in ["coverage report", "coverage xml", "sdist", "bdist"]): continue
            if t.startswith("cd "):
                d = t.split("cd ")[1].strip()
                if d in ["your-repo", "project", "repo"] or not os.path.exists(d): continue

            # Path normalization
            if "requirements.txt" in t:
                p = f"{stack.base_dir}/requirements.txt" if stack.base_dir else "requirements.txt"
                if os.path.exists(p):
                    t = t.replace("requirements.txt", p)
                    if "python" in lang: valid_commands.append("pip install pytest pytest-cov")
                else: continue
            
            if "setup.py" in t:
                p = f"{stack.base_dir}/setup.py" if stack.base_dir else "setup.py"
                if os.path.exists(p): t = t.replace("setup.py", p)
                else: continue
            
            if "pytest" in t or "unittest" in t:
                pts = [f"{stack.base_dir}/tests", "src/tests", "tests", stack.base_dir]
                ft = next((d for d in pts if d and os.path.exists(d)), ".")
                if "pytest" in t: t = f"python -m pytest {ft} || echo 'No tests found'"
                else: t = f"python -m unittest discover -s {ft} -p 'test_*.py' || echo 'No tests found'"
            
            if "bash" in lang and "test.sh" in t:
                t = f"./{t.lstrip('./')} || echo 'Bash tests failed'"

            valid_commands.append(t)
    except Exception:
        valid_commands.append("ls -R")

    # Dedup and Indent
    unique_commands = []
    for c in valid_commands:
        if c not in unique_commands: unique_commands.append(c)
    indented_commands = "\n".join(["          " + c.strip() for c in unique_commands])

    # Build YAML line by line to avoid f-string escaping hell
    yml = []
    yml.append("name: CI Pipeline")
    yml.append("on:")
    yml.append("  push:")
    yml.append("    branches: [ main, develop ]")
    yml.append("jobs:")
    
    # Security Job
    yml.append("  Security:")
    yml.append("    runs-on: ubuntu-latest")
    yml.append("    env:")
    yml.append("      SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}")
    yml.append("    steps:")
    yml.append("      - name: Checkout code")
    yml.append("        uses: actions/checkout@v4")
    yml.append("      - name: GitLeaks Scan")
    yml.append("        uses: gitleaks/gitleaks-action@v2")
    yml.append("        continue-on-error: true")
    if snyk_action:
        yml.append("      - name: Snyk Scan")
        yml.append("        if: ${{ env.SNYK_TOKEN != '' }}")
        yml.append(f"        uses: snyk/actions/{snyk_action}@v0.4.0")
        yml.append("        continue-on-error: true")
        yml.append("        env:")
        yml.append("          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}")

    # Build and Test Job
    yml.append("")
    yml.append("  Build_and_Test:")
    yml.append("    runs-on: ubuntu-latest")
    yml.append("    env:")
    yml.append("      SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}")
    yml.append("      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}")
    yml.append("    steps:")
    yml.append("      - name: Checkout code")
    yml.append("        uses: actions/checkout@v4")
    
    if "bash" in lang:
        yml.append("      - name: ShellCheck")
        yml.append("        uses: ludeeus/action-shellcheck@v2")
        yml.append("        continue-on-error: true")
    else:
        setup_action = "actions/setup-python@v5" if "python" in lang else "actions/setup-dotnet@v4" if "c#" in lang or "net" in lang else "actions/setup-node@v4"
        v_key = "python-version" if "python" in lang else "dotnet-version" if "c#" in lang or "net" in lang else "node-version"
        v_val = stack.language_version or ("3.11" if "python" in lang else "9.0" if "c#" in lang else "20")
        yml.append("      - name: Setup Environment")
        yml.append(f"        uses: {setup_action}")
        yml.append("        with:")
        yml.append(f"          {v_key}: '{v_val}'")

    yml.append("      - name: Install and Test")
    yml.append("        run: |")
    if "python" in lang:
        yml.append(f"          export PYTHONPATH=$PYTHONPATH:$(pwd)/src:$(pwd)/{stack.base_dir}")
    yml.append(indented_commands)
    
    yml.append("      - name: SonarCloud Scan")
    yml.append("        if: ${{ env.SONAR_TOKEN != '' }}")
    yml.append("        uses: sonarsource/sonarcloud-github-action@v3")
    yml.append("        continue-on-error: true")
    yml.append("        env:")
    yml.append("          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}")
    yml.append("          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}")

    # Conditional Jobs
    if stack.has_api:
        yml.append("")
        yml.append("  API_Compliance:")
        yml.append("    runs-on: ubuntu-latest")
        yml.append("    needs: Build_and_Test")
        yml.append("    steps:")
        yml.append("      - name: Checkout code")
        yml.append("        uses: actions/checkout@v4")
        yml.append("      - name: Lint API")
        yml.append(f"        run: npx @stoplight/spectral-cli lint {stack.api_spec_path}")
        yml.append("        continue-on-error: true")

    if stack.container:
        yml.append("")
        yml.append("  Docker:")
        yml.append("    runs-on: ubuntu-latest")
        yml.append("    needs: Build_and_Test")
        yml.append("    steps:")
        yml.append("      - name: Checkout code")
        yml.append("        uses: actions/checkout@v4")
        yml.append("      - name: Build")
        yml.append(f"        run: docker build -t project:{stack.project_version} .")

    yml.append("")
    yml.append("  Reporting:")
    yml.append("    runs-on: ubuntu-latest")
    yml.append("    needs: Build_and_Test")
    yml.append("    steps:")
    yml.append("      - name: Summary")
    yml.append("        run: |")
    yml.append(f"          echo '## Project Version: {stack.project_version}' >> $GITHUB_STEP_SUMMARY")

    return "\n".join(yml).strip()
