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 resilient 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"
    snyk_action = "python" if "python" in lang else "dotnet" if "c#" in lang or "net" in lang else "node" if "node" in lang else "bash"
    
    # Configuration based on language
    if "bash" in lang:
        setup_block = "      - uses: actions/checkout@v4\n      - name: ShellCheck\n        uses: ludeeus/action-shellcheck@master"
    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"
        setup_version_key = "python-version" if "python" in lang else "dotnet-version" if "c#" in lang or "net" in lang else "node-version"
        setup_version_val = stack.language_version or ("3.11" if "python" in lang else "9.0" if "c#" in lang else "20")
        setup_block = f"      - uses: actions/checkout@v4\n      - uses: {setup_action}\n        with:\n          {setup_version_key}: '{setup_version_val}'"

    # 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. NO EXPLANATIONS. 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()
            # Filter non-commands
            if not t or not any(t.startswith(c) for c in ["dotnet", "npm", "pip", "pytest", "python", "cd ", "mkdir ", "ls ", "bash ", "chmod ", "./"]):
                continue
            
            # --- PREVENT HALLUCINATIONS ---
            # Remove generic 'cd your-repo' or non-existent dirs
            if t.startswith("cd "):
                target_dir = t.split("cd ")[1].strip()
                if target_dir in ["your-repo", "project", "repo", "my-app"] or not os.path.exists(target_dir):
                    continue

            # --- INTELLIGENT PATH VERIFICATION ---
            if "requirements.txt" in t:
                req_path = f"{stack.base_dir}/requirements.txt" if stack.base_dir else "requirements.txt"
                if os.path.exists(req_path):
                    t = t.replace("requirements.txt", req_path)
                    if "python" in lang: valid_commands.append("pip install pytest pytest-cov")
                else: continue
            
            if "setup.py" in t:
                setup_path = f"{stack.base_dir}/setup.py" if stack.base_dir else "setup.py"
                if os.path.exists(setup_path): t = t.replace("setup.py", setup_path)
                else: continue
            
            # --- RESILIENT TEST EXECUTION ---
            if "pytest" in t or "unittest" in t:
                possible_tests = [f"{stack.base_dir}/tests", "src/tests", "tests", stack.base_dir]
                found_test = next((d for d in possible_tests if d and os.path.exists(d)), ".")
                
                if "pytest" in t:
                    t = f"python -m pytest {found_test} || echo 'No tests found, skipping...'"
                else:
                    t = f"python -m unittest discover -s {found_test} -p 'test_*.py' || echo 'No tests found, skipping...'"
            
            if "bash" in lang and "test.sh" in t:
                t = f"./{t.lstrip('./')} || echo 'Bash tests failed or not found'"

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

    # Final cleanup: Remove duplicates and normalize indentation
    valid_commands = list(dict.fromkeys(valid_commands))
    indented_commands = "\n".join(["          " + c.strip() for c in valid_commands])

    # Build the YAML
    python_path_fix = f"export PYTHONPATH=$PYTHONPATH:$(pwd)/src:$(pwd)/{stack.base_dir}\n          " if "python" in lang else ""

    yaml = f"name: CI Pipeline\n"
    yaml += "on:\n  push:\n    branches: [ main, develop ]\n"
    yaml += "env:\n  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n  SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}\n  SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}\n"
    yaml += "jobs:\n"
    
    yaml += "  Security:\n    runs-on: ubuntu-latest\n    steps:\n"
    yaml += "      - uses: actions/checkout@v4\n"
    yaml += "      - uses: gitleaks/gitleaks-action@v2\n        continue-on-error: true\n"
    yaml += f"      - name: Snyk Scan\n        if: env.SNYK_TOKEN != ''\n        uses: snyk/actions/{snyk_action}@master\n"
    yaml += "        continue-on-error: true\n"
    yaml += "        env:\n          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}\n\n"

    yaml += "  Build_and_Test:\n    runs-on: ubuntu-latest\n    steps:\n"
    yaml += setup_block + "\n"
    yaml += "      - name: Install and Test\n        run: |\n"
    yaml += f"          {python_path_fix}" + indented_commands + "\n"
    yaml += "      - name: SonarCloud\n        if: env.SONAR_TOKEN != ''\n        uses: sonarsource/sonarcloud-github-action@master\n"
    yaml += "        continue-on-error: true\n"
    yaml += "        env:\n          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}\n\n"

    if stack.has_api:
        yaml += "  API_Compliance:\n    runs-on: ubuntu-latest\n    needs: Build_and_Test\n    steps:\n"
        yaml += "      - uses: actions/checkout@v4\n"
        yaml += f"      - name: Lint API\n        run: npx @stoplight/spectral-cli lint {stack.api_spec_path}\n        continue-on-error: true\n\n"

    if stack.container:
        yaml += "  Docker:\n    runs-on: ubuntu-latest\n    needs: Build_and_Test\n    steps:\n"
        yaml += "      - uses: actions/checkout@v4\n"
        yaml += f"      - name: Build\n        run: docker build -t project:{stack.project_version} .\n\n"

    yaml += "  Reporting:\n    runs-on: ubuntu-latest\n    needs: Build_and_Test\n    steps:\n"
    yaml += "      - name: Summary\n"
    yaml += "        run: |\n"
    yaml += f"          echo '## Project Version: {stack.project_version}' >> $GITHUB_STEP_SUMMARY\n"

    return yaml.strip()
