"""
Address-related activities for platform worker.

These activities handle:
- Creating addresses in Django Teams service
- Creating nodes in ArangoDB
- Triggering Prefect sync_node flow
- Updating address status
"""

import logging
import time

import httpx
from temporalio import activity

from optovia_workflows.types import (
    CreateAddressInDjangoInput,
    CreateAddressInDjangoResult,
    TriggerPrefectSyncInput,
    TriggerPrefectSyncResult,
    UpdateAddressStatusInput,
    UpdateAddressStatusResult,
)

from ..config import settings

logger = logging.getLogger(__name__)


CREATE_ADDRESS_MUTATION = """
mutation CreateAddressFromWorkflow(
    $workflowId: String!,
    $teamUuid: String!,
    $name: String!,
    $address: String!,
    $latitude: Float,
    $longitude: Float,
    $countryCode: String,
    $isDefault: Boolean
) {
    createAddressFromWorkflow(
        workflowId: $workflowId,
        teamUuid: $teamUuid,
        name: $name,
        address: $address,
        latitude: $latitude,
        longitude: $longitude,
        countryCode: $countryCode,
        isDefault: $isDefault
    ) {
        success
        addressUuid
        message
    }
}
"""


UPDATE_ADDRESS_STATUS_MUTATION = """
mutation UpdateAddressStatus(
    $addressUuid: String!,
    $status: String!,
    $errorMessage: String
) {
    updateAddressStatus(
        addressUuid: $addressUuid,
        status: $status,
        errorMessage: $errorMessage
    ) {
        success
        message
    }
}
"""


@activity.defn(name="create_address_in_django")
def create_address_in_django(data: CreateAddressInDjangoInput) -> CreateAddressInDjangoResult:
    """
    Create TeamAddress in Django Teams service via GraphQL M2M endpoint.
    """
    url = f"http://{settings.TEAMS_INTERNAL_URL}/graphql/m2m/"

    logger.info(
        "Creating address for team %s (workflow=%s)",
        data.team_uuid,
        data.workflow_id,
    )

    with httpx.Client(timeout=settings.TEAMS_TIMEOUT) as client:
        response = client.post(
            url,
            json={
                "query": CREATE_ADDRESS_MUTATION,
                "variables": {
                    "workflowId": data.workflow_id,
                    "teamUuid": data.team_uuid,
                    "name": data.name,
                    "address": data.address,
                    "latitude": data.latitude,
                    "longitude": data.longitude,
                    "countryCode": data.country_code,
                    "isDefault": data.is_default,
                },
            },
            headers={"Content-Type": "application/json"},
        )
        response.raise_for_status()

        result = response.json()
        if "errors" in result:
            error_msg = str(result["errors"])
            logger.error("GraphQL errors: %s", error_msg)
            return CreateAddressInDjangoResult(success=False, message=error_msg)

        mutation_result = result.get("data", {}).get("createAddressFromWorkflow", {})
        if not mutation_result.get("success"):
            msg = mutation_result.get("message", "Unknown error")
            return CreateAddressInDjangoResult(success=False, message=msg)

        address_uuid = mutation_result.get("addressUuid", "")
        logger.info("Created address %s for team %s", address_uuid, data.team_uuid)

        return CreateAddressInDjangoResult(
            success=True,
            address_uuid=address_uuid,
        )


@activity.defn(name="update_address_status")
def update_address_status(data: UpdateAddressStatusInput) -> UpdateAddressStatusResult:
    """
    Update address status in Django Teams service via GraphQL M2M endpoint.
    """
    url = f"http://{settings.TEAMS_INTERNAL_URL}/graphql/m2m/"

    logger.info(
        "Updating address %s status to %s",
        data.address_uuid,
        data.status,
    )

    with httpx.Client(timeout=settings.TEAMS_TIMEOUT) as client:
        response = client.post(
            url,
            json={
                "query": UPDATE_ADDRESS_STATUS_MUTATION,
                "variables": {
                    "addressUuid": data.address_uuid,
                    "status": data.status,
                    "errorMessage": data.error_message,
                },
            },
            headers={"Content-Type": "application/json"},
        )
        response.raise_for_status()

        result = response.json()
        if "errors" in result:
            error_msg = str(result["errors"])
            logger.error("GraphQL errors: %s", error_msg)
            return UpdateAddressStatusResult(success=False, message=error_msg)

        mutation_result = result.get("data", {}).get("updateAddressStatus", {})
        if not mutation_result.get("success"):
            msg = mutation_result.get("message", "Unknown error")
            return UpdateAddressStatusResult(success=False, message=msg)

        return UpdateAddressStatusResult(success=True)


@activity.defn(name="trigger_prefect_sync")
def trigger_prefect_sync(data: TriggerPrefectSyncInput) -> TriggerPrefectSyncResult:
    """
    Trigger Prefect sync_node flow for isochrone/route calculations.

    Waits for the flow run to complete by polling Prefect API.

    If node data (name, lat, lon, etc.) is provided, passes it directly to Prefect.
    Otherwise, passes only node_uuid and Prefect will fetch from Odoo.
    """
    logger.info("Triggering Prefect sync for node %s", data.node_uuid)

    try:
        # Get deployment ID
        deployment_url = f"{settings.PREFECT_API_URL}/deployments/name/sync-node/sync-node-deployment"

        with httpx.Client(timeout=30) as client:
            response = client.get(deployment_url)
            response.raise_for_status()
            deployment_id = response.json()["id"]

            # Build parameters based on available data
            if data.name and data.latitude and data.longitude:
                # User address - pass full node_data to Prefect
                node_data = {
                    "uuid": data.node_uuid,
                    "name": data.name,
                    "latitude": data.latitude,
                    "longitude": data.longitude,
                    "country_code": data.country_code,
                    "transport_types": ["auto"],  # User addresses support auto only
                    "node_type": data.node_type or "buyer",  # Default to buyer
                    "team_uuid": data.team_uuid,
                }
                parameters = {"node_data": node_data}
                logger.info(
                    "Triggering Prefect sync with node_data for %s (type=%s)",
                    data.node_uuid,
                    node_data["node_type"],
                )
            else:
                # Logistics node - pass only UUID, Prefect will fetch from Odoo
                parameters = {"node_uuid": data.node_uuid}
                logger.info(
                    "Triggering Prefect sync with node_uuid for %s (will fetch from Odoo)",
                    data.node_uuid,
                )

            # Create flow run
            run_url = f"{settings.PREFECT_API_URL}/deployments/{deployment_id}/create_flow_run"
            response = client.post(
                run_url,
                json={"parameters": parameters},
            )
            response.raise_for_status()
            flow_run = response.json()
            flow_run_id = flow_run["id"]

            logger.info(
                "Created Prefect flow run %s for node %s, waiting for completion...",
                flow_run_id,
                data.node_uuid,
            )

        # Poll for flow run completion
        # Terminal states: COMPLETED, FAILED, CANCELLED, CRASHED
        poll_interval = 60  # seconds
        max_polls = 30  # 30 minutes max (30 * 60s)
        polls = 0

        while polls < max_polls:
            try:
                with httpx.Client(timeout=30) as client:
                    flow_run_url = f"{settings.PREFECT_API_URL}/flow_runs/{flow_run_id}"
                    response = client.get(flow_run_url)
                    response.raise_for_status()
                    flow_run = response.json()

                    state_type = flow_run.get("state", {}).get("type")
                    state_name = flow_run.get("state", {}).get("name", "")

                    if state_type == "COMPLETED":
                        logger.info(
                            "Prefect flow run %s completed successfully for node %s",
                            flow_run_id,
                            data.node_uuid,
                        )
                        return TriggerPrefectSyncResult(
                            success=True,
                            flow_run_id=flow_run_id,
                        )
                    elif state_type in ("FAILED", "CANCELLED", "CRASHED"):
                        error_msg = f"Flow run {state_type}: {state_name}"
                        logger.error(
                            "Prefect flow run %s failed for node %s: %s",
                            flow_run_id,
                            data.node_uuid,
                            error_msg,
                        )
                        return TriggerPrefectSyncResult(
                            success=False,
                            flow_run_id=flow_run_id,
                            message=error_msg,
                        )
                    else:
                        # Still running (PENDING, RUNNING, etc.)
                        if polls % 5 == 0:  # Log every 5 minutes
                            logger.info(
                                "Flow run %s for node %s still running (state=%s), poll %d/%d",
                                flow_run_id,
                                data.node_uuid,
                                state_type,
                                polls + 1,
                                max_polls,
                            )

                        polls += 1
                        time.sleep(poll_interval)

            except Exception as poll_error:
                logger.warning(
                    "Error polling flow run %s: %s, retrying...",
                    flow_run_id,
                    poll_error,
                )
                polls += 1
                time.sleep(poll_interval)

        # Timeout reached
        timeout_msg = f"Timeout waiting for flow run {flow_run_id} after {max_polls * poll_interval}s"
        logger.error(timeout_msg)
        return TriggerPrefectSyncResult(
            success=False,
            flow_run_id=flow_run_id,
            message=timeout_msg,
        )

    except Exception as e:
        logger.error("Failed to trigger Prefect sync: %s", e)
        return TriggerPrefectSyncResult(
            success=False,
            message=str(e),
        )
