"""Flow Deployer - Deploy Flow XML via Salesforce Metadata API."""

from __future__ import annotations

import asyncio
import logging
from typing import Any, Dict, List, Optional

from ..api.v2.flow_builder_schemas import DeployResponse
from .flow_compiler import build_deploy_zip
from .salesforce_gateway import SalesforceGateway

log = logging.getLogger(__name__)

# Polling configuration
# Production orgs with many tests can take 2-3+ minutes
MAX_POLL_ATTEMPTS = 60  # 60 attempts
POLL_INTERVAL_SECONDS = 3  # 3 seconds between polls
# Total max wait: 180 seconds (3 minutes)


class FlowDeployer:
    def __init__(self, gateway: SalesforceGateway) -> None:
        self.gateway = gateway

    async def start_deploy(self, flow_xml: str, flow_api_name: str) -> DeployResponse:
        """Start a Flow deployment and return immediately with deployment_id."""
        zip_bytes = build_deploy_zip(flow_xml, flow_api_name)

        result = await self.gateway.deploy_metadata(zip_bytes)
        deployment_id = None
        if isinstance(result, dict):
            deployment_id = result.get("id") or result.get("deployment_id")

        if not deployment_id:
            return DeployResponse(
                success=False,
                deployment_id=None,
                flow_id=None,
                status="failed",
                error="No deployment ID returned from Salesforce",
                warnings=[],
            )

        log.info("Flow deploy initiated (async): %s", deployment_id)
        return DeployResponse(
            success=True,
            deployment_id=deployment_id,
            flow_id=None,
            status="pending",
            error=None,
            warnings=[],
        )

    async def deploy_flow(self, flow_xml: str, flow_api_name: str) -> DeployResponse:
        """Deploy a Flow and wait for completion."""
        zip_bytes = build_deploy_zip(flow_xml, flow_api_name)

        # Initiate the deploy
        result = await self.gateway.deploy_metadata(zip_bytes)

        deployment_id = None
        if isinstance(result, dict):
            deployment_id = result.get("id") or result.get("deployment_id")

        if not deployment_id:
            return DeployResponse(
                success=False,
                deployment_id=None,
                flow_id=None,
                status="failed",
                error="No deployment ID returned from Salesforce",
                warnings=[],
            )

        log.info("Flow deploy initiated: %s, polling for completion...", deployment_id)

        # Poll for completion
        final_result = await self._poll_for_completion(deployment_id)

        return DeployResponse(
            success=final_result.get("success", False),
            deployment_id=deployment_id,
            flow_id=None,
            status=final_result.get("status", "unknown"),
            error=final_result.get("error_message"),
            warnings=final_result.get("errors", []) if not final_result.get("success") else [],
        )

    async def _poll_for_completion(self, deployment_id: str) -> Dict[str, Any]:
        """Poll checkDeployStatus until done or timeout."""
        for attempt in range(MAX_POLL_ATTEMPTS):
            try:
                status = await self.gateway.check_deploy_status(deployment_id)

                if status.get("done"):
                    if status.get("success"):
                        log.info("Flow deploy succeeded: %s", deployment_id)
                    else:
                        log.warning(
                            "Flow deploy failed: %s - %s",
                            deployment_id,
                            status.get("error_message"),
                        )
                    return status

                log.debug(
                    "Deploy %s in progress (attempt %d/%d): %s",
                    deployment_id,
                    attempt + 1,
                    MAX_POLL_ATTEMPTS,
                    status.get("status"),
                )

            except Exception as exc:
                log.warning("Error checking deploy status: %s", exc)
                # Continue polling on transient errors

            await asyncio.sleep(POLL_INTERVAL_SECONDS)

        # Timeout - return last known status
        log.warning("Deploy %s polling timeout after %d attempts", deployment_id, MAX_POLL_ATTEMPTS)
        return {
            "done": False,
            "success": False,
            "status": "Timeout",
            "error_message": f"Deployment timed out after {MAX_POLL_ATTEMPTS * POLL_INTERVAL_SECONDS} seconds. Check Salesforce Setup for status.",
        }
