"""Setup automation orchestrator tool (UI + API + Security)."""

from __future__ import annotations

import json
from datetime import datetime, timezone
from typing import Any

from mcp.types import TextContent, Tool

from maeris_mcp.auth.token_store import TokenStore
from maeris_mcp.storage.api_store import APIStore
from maeris_mcp.storage.execution_store import TestExecutionStore
from maeris_mcp.storage.security_store import SecurityScanStore
from maeris_mcp.storage.test_store import TestGenerationStore
from maeris_mcp.tools.maeris_sync import handle_push_to_maeris
from maeris_mcp.tools.portal_api_tools import handle_add_apis_bulk
from maeris_mcp.tools.test_push import handle_push_tests_to_maeris


def setup_automation_tool() -> Tool:
    """Return the tool definition for setup_automation."""
    return Tool(
        name="setup_automation",
        description=(
            "Orchestrates UI automation, API automation, and repository security scan setup. "
            "Use when the user says 'setup automation' or 'setup my automation' for full setup. "
            "Do not use for API-only or 'API automation' requests; use setup_api_automation instead. "
            "This tool coordinates the flow and provides the checklist to push to Maeris.\n\n"
            "IMPORTANT: When stage='start' and selected_items is NOT provided, this tool returns "
            "a pendingDecision with the 3 available automation options. You MUST present these options "
            "to the user and WAIT for their reply before calling again. Do NOT assume 'all 3' — "
            "always ask. Once the user replies, call again with stage='start' and selected_items "
            "set to only the options the user chose."
        ),
        inputSchema={
            "type": "object",
            "properties": {
                "stage": {
                    "type": "string",
                    "enum": ["start", "status", "checklist", "push"],
                    "description": "Stage of the setup flow.",
                },
                "selected_items": {
                    "type": "array",
                    "items": {
                        "type": "string",
                        "enum": ["ui_tests", "api_collection", "security_scan"],
                    },
                    "description": (
                        "The automation types the user chose to set up. "
                        "Valid values: 'ui_tests', 'api_collection', 'security_scan'. "
                        "Only set after presenting options to the user and receiving their reply. "
                        "Required on the second stage='start' call."
                    ),
                },
                "target_path": {
                    "type": "string",
                    "description": "Absolute path to scan (defaults to server working directory).",
                },
                "flow_description": {
                    "type": "string",
                    "description": (
                        "Optional. Specific flow to focus on (e.g., 'login flow'). "
                        "If omitted, Maeris auto-detects ALL testable flows in the codebase."
                    ),
                },
                "base_url": {
                    "type": "string",
                    "description": "Base URL for UI tests (e.g., https://light-dev.up.railway.app).",
                },
                "api_collection_name": {
                    "type": "string",
                    "description": "Collection name to store extracted APIs in Maeris.",
                },
                "scan_profile": {
                    "type": "string",
                    "description": "Security scan profile (default: all_static).",
                },
                "ui_session_id": {
                    "type": "string",
                    "description": "Test generation session ID (generate_tests).",
                },
                "exec_session_id": {
                    "type": "string",
                    "description": "Optional execution session ID (run_and_fix_tests).",
                },
                "api_storage_id": {
                    "type": "string",
                    "description": "API scan storage ID (from api_scan final response).",
                },
                "security_scan_id": {
                    "type": "string",
                    "description": "Security scan ID (from security_scan final response).",
                },
                "push_items": {
                    "type": "array",
                    "items": {"type": "string"},
                    "description": "Checklist items to push: ui_tests, api_collection, security_scan.",
                },
            },
        },
    )


def _latest_completed_ui_session(test_store: TestGenerationStore) -> str | None:
    for s in test_store.get_recent(20):
        if s.status == "completed":
            return s.session_id
    return None


def _latest_api_storage_id(api_store: APIStore) -> str | None:
    all_lists = api_store.get_all()
    if not all_lists:
        return None
    # Pick most recent by stored_at
    all_lists.sort(key=lambda s: s.stored_at, reverse=True)
    return all_lists[0].id


def _latest_security_scan_id(security_store: SecurityScanStore) -> str | None:
    scans = security_store.get_recent(20)
    for s in scans:
        if s.status == "completed":
            return s.id
    return None


async def handle_setup_automation(
    test_store: TestGenerationStore,
    api_store: APIStore,
    security_store: SecurityScanStore,
    exec_store: TestExecutionStore,
    arguments: dict,
) -> list[TextContent]:
    """Handle setup_automation tool call."""
    stage = (arguments.get("stage") or "start").lower()
    target_path = arguments.get("target_path") or arguments.get("targetPath")
    flow_description = arguments.get("flow_description") or arguments.get("flowDescription")
    base_url = arguments.get("base_url") or arguments.get("baseUrl")
    api_collection_name = arguments.get("api_collection_name") or arguments.get("apiCollectionName")
    scan_profile = arguments.get("scan_profile") or arguments.get("scanProfile")

    ui_session_id = arguments.get("ui_session_id") or arguments.get("uiSessionId")
    exec_session_id = arguments.get("exec_session_id") or arguments.get("execSessionId")
    api_storage_id = arguments.get("api_storage_id") or arguments.get("apiStorageId")
    security_scan_id = arguments.get("security_scan_id") or arguments.get("securityScanId")
    push_items = arguments.get("push_items") or arguments.get("pushItems") or []

    if stage == "start":
        selected_items = arguments.get("selected_items") or arguments.get("selectedItems") or []

        # No selection yet — present options and wait for user's choice
        if not selected_items:
            prompt = {
                "status": "awaiting_selection",
                "message": "What would you like to automate? Choose one or more of the options below:",
                "options": [
                    {
                        "id": "ui_tests",
                        "label": "UI Tests",
                        "description": (
                            "Scans your codebase, discovers all user-facing flows (login, forms, CRUD, "
                            "navigation, etc.) and generates Playwright E2E test cases."
                        ),
                    },
                    {
                        "id": "api_collection",
                        "label": "API Automation",
                        "description": (
                            "Extracts all HTTP API endpoints from your repo, groups them into meaningful "
                            "user-journey flows, and sets up environment configs — ready to run in Maeris."
                        ),
                    },
                    {
                        "id": "security_scan",
                        "label": "Security Scan",
                        "description": (
                            "Scans your codebase for secrets, vulnerable patterns, and dependency issues "
                            "using static analysis."
                        ),
                    },
                ],
                "pendingDecision": {
                    "question": "Which of the above would you like to set up? You can pick any combination.",
                    "hint": (
                        "Reply with your choice (e.g. 'UI tests and API', 'all three', 'just security'). "
                        "Then call setup_automation again with stage='start' and selected_items=[...] "
                        "set to the IDs the user chose."
                    ),
                },
            }
            return [TextContent(type="text", text=json.dumps(prompt, indent=2))]

        # User has made a selection — build nextActions only for chosen items
        valid_items = {"ui_tests", "api_collection", "security_scan"}
        chosen = [item for item in selected_items if item in valid_items]
        if not chosen:
            return [TextContent(
                type="text",
                text=json.dumps({
                    "status": "error",
                    "message": (
                        f"None of the provided selected_items are valid: {selected_items}. "
                        "Valid values are: ui_tests, api_collection, security_scan."
                    ),
                }, indent=2),
            )]

        if not flow_description:
            flow_description = "all user flows"

        next_actions = []

        if "ui_tests" in chosen:
            next_actions.append({
                "tool": "generate_tests",
                "arguments": {
                    "flow_description": flow_description,
                    "target_path": target_path,
                    "include_content": True,
                    "offset": 0,
                    "limit": 5,
                    "max_test_cases": 50,
                },
                "notes": (
                    "Follow the generate_tests multi-phase workflow. "
                    "REQUIRED STEP BEFORE is_last=true: After scanning all file batches (hasMore=false), "
                    "you MUST output a plain-text message to the user in this exact format:\n"
                    "  'Maeris detected the following flows in your codebase:\n"
                    "   • <Flow 1 name>\n"
                    "   • <Flow 2 name>\n"
                    "   ...\n"
                    "   Generating test cases for all flows now...'\n"
                    "Only AFTER sending that message should you call generate_tests with is_last=true. "
                    "Discover ALL testable flows and generate appropriate positive + negative tests per flow "
                    "(1+1 for simple, 1+2 for medium, 1+3 for complex). Do NOT stop at 2 total."
                ),
            })

        if "api_collection" in chosen:
            next_actions.append({
                "tool": "setup_api_automation",
                "arguments": {
                    "target_path": target_path,
                    "include_content": True,
                    "offset": 0,
                    "limit": 5,
                },
                "notes": (
                    "Follow the setup_api_automation multi-phase workflow:\n"
                    "Phase 1 (Scanning): Call with target_path + include_content=true + offset=0. "
                    "Analyze each file batch and pass apis=[...found] alongside the next offset. "
                    "Repeat until hasMore=false. On the final batch, also submit flows=[] and environments=[], then set is_last=true.\n"
                    "Phase 2 (Review): Present the scanned APIs, flows, and environments to the user. "
                    "Ask the user to confirm or adjust the selection.\n"
                    "Phase 3 (Save): Ask the user for a collection_name, then call with collection_name + approve=true to save directly to Maeris. "
                    "setup_api_automation saves the API collection directly — no separate push step is needed."
                ),
            })

        if "security_scan" in chosen:
            next_actions.append({
                "tool": "security_scan",
                "arguments": {
                    "target_path": target_path,
                    "scan_profile": scan_profile or "all_static",
                    "include_content": True,
                    "offset": 0,
                    "limit": 5,
                },
                "notes": "Follow the security_scan multi-phase workflow until is_last=true.",
            })

        next_step = (
            "Once all selected scans wrap up, call setup_automation with stage='checklist' to review everything before pushing."
            if len(chosen) > 1 else
            "Once the scan wraps up, call setup_automation with stage='checklist' to review before pushing."
        )

        plan = {
            "status": "starting",
            "selectedItems": chosen,
            "message": (
                f"Got it — setting up: {', '.join(chosen)}. "
                "Let's scan your codebase and get everything configured."
            ),
            "nextActions": next_actions,
            "nextStep": next_step,
        }
        return [TextContent(type="text", text=json.dumps(plan, indent=2))]

    # Resolve most recent IDs if not provided
    if not ui_session_id:
        ui_session_id = _latest_completed_ui_session(test_store)
    if not api_storage_id:
        api_storage_id = _latest_api_storage_id(api_store)
    if not security_scan_id:
        security_scan_id = _latest_security_scan_id(security_store)

    if stage in ("status", "checklist"):
        status = {
            "ui_tests_ready": bool(ui_session_id),
            "api_collection_ready": bool(api_storage_id),
            "security_scan_ready": bool(security_scan_id),
            "ui_session_id": ui_session_id,
            "api_storage_id": api_storage_id,
            "security_scan_id": security_scan_id,
        }

        if stage == "status":
            return [TextContent(type="text", text=json.dumps(status, indent=2))]

        # stage == checklist
        token_store = TokenStore()
        if not token_store.is_authenticated():
            return [TextContent(
                type="text",
                text=(
                    "Everything's scanned and ready to go — but you're not logged in yet! "
                    "Run `maeris login` to connect your account, then we'll pick up right where we left off."
                ),
            )]

        checklist = [
            {"id": "ui_tests", "label": "UI tests", "ready": bool(ui_session_id)},
            {"id": "api_collection", "label": "API collection", "ready": bool(api_storage_id)},
            {"id": "security_scan", "label": "Security scan", "ready": bool(security_scan_id)},
        ]
        ready_ids = [c["id"] for c in checklist if c["ready"]]
        response = {
            "status": "setup_completed",
            "message": (
                "Automation setup is done! Here's what's ready to push to Maeris. "
                "Only the items marked ready=true can be pushed."
            ),
            "checklist": checklist,
            "readyToPush": ready_ids,
            "pendingDecision": {
                "question": (
                    f"The following items are ready: {ready_ids}. "
                    "Which of these would you like to push to Maeris?"
                ),
                "hint": (
                    "After the user confirms, call setup_automation with stage='push' and "
                    "push_items set to only the items the user chose from the ready list."
                ),
            },
        }
        return [TextContent(type="text", text=json.dumps(response, indent=2))]

    if stage == "push":
        token_store = TokenStore()
        if not token_store.is_authenticated():
            return [TextContent(
                type="text",
                text="Looks like you're not logged in yet. Run `maeris login` to connect, then we can push everything over.",
            )]

        results: dict[str, Any] = {"pushed": [], "failed": []}

        if "ui_tests" in push_items:
            if not ui_session_id:
                results["failed"].append("ui_tests: no completed test session found — run generate_tests first")
            else:
                out = await handle_push_tests_to_maeris(
                    test_store,
                    exec_store,
                    {
                        "session_id": ui_session_id,
                        "exec_session_id": exec_session_id,
                    },
                )
                results["pushed"].append({"ui_tests": out[0].text if out else ""})

        if "api_collection" in push_items:
            if not api_storage_id:
                results["failed"].append("api_collection: no API scan results found — run api_scan first")
            else:
                stored = api_store.get(api_storage_id)
                if not stored or not stored.collection:
                    results["failed"].append("api_collection: the stored API data seems empty — try running the API scan again")
                else:
                    apis_payload = [a.model_dump(by_alias=True) for a in stored.collection.apis]
                    collection_name = api_collection_name or stored.collection.project_name or stored.name
                    out = await handle_add_apis_bulk(
                        {"collection_name": collection_name, "apis": apis_payload}
                    )
                    results["pushed"].append({"api_collection": out[0].text if out else ""})

        if "security_scan" in push_items:
            if not security_scan_id:
                results["failed"].append("security_scan: no completed security scan found — run security_scan first")
            else:
                out = await handle_push_to_maeris(
                    security_store,
                    {"data_type": "vulnerabilities", "scan_id": security_scan_id},
                )
                results["pushed"].append({"security_scan": out[0].text if out else ""})

        pushed_count = len(results["pushed"])
        failed_count = len(results["failed"])
        if failed_count == 0:
            message = f"All done — {pushed_count} item{'s' if pushed_count != 1 else ''} pushed to Maeris! You're all set."
        else:
            message = (
                f"Pushed {pushed_count} item{'s' if pushed_count != 1 else ''} to Maeris, "
                f"but {failed_count} had issues. Check the details below."
            )
        response = {
            "status": "pushed",
            "timestamp": datetime.now(timezone.utc).isoformat(),
            "results": results,
            "message": message,
            "nextStep": "Head over to the Maeris dashboard to see everything in action!",
        }
        return [TextContent(type="text", text=json.dumps(response, indent=2))]

    return [TextContent(type="text", text=f"Hmm, I don't recognize the stage '{stage}'. Try one of: start, status, checklist, or push.")]
