"""
Offer Workflow.

Creates an offer in Exchange, stores description in Terminus, and
syncs offer node/edge in graph via Prefect.
"""
from datetime import timedelta

from temporalio import workflow
from temporalio.common import RetryPolicy
from temporalio.exceptions import ApplicationError

with workflow.unsafe.imports_passed_through():
    from ..types import (
        OfferData,
        OfferWorkflowResult,
        CreateOfferInExchangeInput,
        CreateOfferInExchangeResult,
        SaveOfferDescriptionInput,
        SaveOfferDescriptionResult,
        TriggerPrefectOfferSyncInput,
        TriggerPrefectOfferSyncResult,
        UpdateOfferWorkflowStatusInput,
    )


EXTERNAL_API_RETRY = RetryPolicy(
    maximum_attempts=5,
    initial_interval=timedelta(seconds=2),
    backoff_coefficient=2.0,
    maximum_interval=timedelta(seconds=30),
)

INTERNAL_API_RETRY = RetryPolicy(
    maximum_attempts=3,
    initial_interval=timedelta(seconds=1),
    backoff_coefficient=2.0,
    maximum_interval=timedelta(seconds=10),
)


@workflow.defn(name="create_offer")
class OfferWorkflow:
    @workflow.run
    async def run(self, data: OfferData) -> OfferWorkflowResult:
        workflow.logger.info("Starting offer workflow %s", data.offer_uuid)

        create_result: CreateOfferInExchangeResult = await workflow.execute_activity(
            "create_offer_in_exchange",
            CreateOfferInExchangeInput(
                offer_uuid=data.offer_uuid,
                team_uuid=data.team_uuid,
                product_uuid=data.product_uuid,
                product_name=data.product_name,
                category_name=data.category_name,
                location_uuid=data.location_uuid,
                location_name=data.location_name,
                location_country=data.location_country,
                location_country_code=data.location_country_code,
                location_latitude=data.location_latitude,
                location_longitude=data.location_longitude,
                quantity=data.quantity,
                unit=data.unit,
                price_per_unit=data.price_per_unit,
                currency=data.currency,
                description=data.description,
                valid_until=data.valid_until,
                terminus_schema_id=data.terminus_schema_id,
                terminus_document_id=data.offer_uuid,
            ),
            schedule_to_close_timeout=timedelta(seconds=30),
            start_to_close_timeout=timedelta(seconds=15),
            retry_policy=INTERNAL_API_RETRY,
        )

        success = create_result.success if hasattr(create_result, "success") else create_result["success"]
        if not success:
            message = create_result.message if hasattr(create_result, "message") else create_result.get("message", "")
            workflow.logger.error("Failed to create offer in Exchange: %s", message)
            raise ApplicationError(f"Failed to create offer in Exchange: {message}", type="CreateOfferFailed")

        # Save description to Terminus
        if data.terminus_schema_id and data.terminus_payload:
            save_result: SaveOfferDescriptionResult = await workflow.execute_activity(
                "save_offer_description",
                SaveOfferDescriptionInput(
                    offer_uuid=data.offer_uuid,
                    schema_id=data.terminus_schema_id,
                    payload=data.terminus_payload,
                ),
                schedule_to_close_timeout=timedelta(seconds=30),
                start_to_close_timeout=timedelta(seconds=15),
                retry_policy=EXTERNAL_API_RETRY,
            )
            save_success = save_result.success if hasattr(save_result, "success") else save_result.get("success", False)
            if not save_success:
                message = save_result.message if hasattr(save_result, "message") else save_result.get("message", "")
                await workflow.execute_activity(
                    "update_offer_workflow_status",
                    UpdateOfferWorkflowStatusInput(
                        offer_uuid=data.offer_uuid,
                        status="error",
                        error_message=message,
                    ),
                    schedule_to_close_timeout=timedelta(seconds=30),
                    start_to_close_timeout=timedelta(seconds=15),
                    retry_policy=INTERNAL_API_RETRY,
                )
                raise ApplicationError(f"Failed to save offer description: {message}", type="SaveOfferDescriptionFailed")
        else:
            workflow.logger.warning("No Terminus payload for offer %s", data.offer_uuid)

        # Sync offer node + edge in graph
        if data.location_uuid and data.location_latitude is not None and data.location_longitude is not None:
            sync_result: TriggerPrefectOfferSyncResult = await workflow.execute_activity(
                "trigger_prefect_offer_sync",
                TriggerPrefectOfferSyncInput(
                    offer_uuid=data.offer_uuid,
                    location_uuid=data.location_uuid,
                    location_latitude=data.location_latitude,
                    location_longitude=data.location_longitude,
                    team_uuid=data.team_uuid,
                    product_uuid=data.product_uuid,
                    price_per_unit=data.price_per_unit,
                    currency=data.currency,
                    quantity=data.quantity,
                    unit=data.unit,
                ),
                schedule_to_close_timeout=timedelta(minutes=20),
                start_to_close_timeout=timedelta(minutes=20),
                retry_policy=EXTERNAL_API_RETRY,
            )
            sync_success = sync_result.success if hasattr(sync_result, "success") else sync_result.get("success", False)
            if not sync_success:
                message = sync_result.message if hasattr(sync_result, "message") else sync_result.get("message", "")
                await workflow.execute_activity(
                    "update_offer_workflow_status",
                    UpdateOfferWorkflowStatusInput(
                        offer_uuid=data.offer_uuid,
                        status="error",
                        error_message=message,
                    ),
                    schedule_to_close_timeout=timedelta(seconds=30),
                    start_to_close_timeout=timedelta(seconds=15),
                    retry_policy=INTERNAL_API_RETRY,
                )
                raise ApplicationError(f"Failed to sync offer in Prefect: {message}", type="PrefectSyncFailed")
        else:
            message = "Offer location coordinates are missing"
            await workflow.execute_activity(
                "update_offer_workflow_status",
                UpdateOfferWorkflowStatusInput(
                    offer_uuid=data.offer_uuid,
                    status="error",
                    error_message=message,
                ),
                schedule_to_close_timeout=timedelta(seconds=30),
                start_to_close_timeout=timedelta(seconds=15),
                retry_policy=INTERNAL_API_RETRY,
            )
            raise ApplicationError(message, type="MissingCoordinates")

        await workflow.execute_activity(
            "update_offer_workflow_status",
            UpdateOfferWorkflowStatusInput(
                offer_uuid=data.offer_uuid,
                status="active",
            ),
            schedule_to_close_timeout=timedelta(seconds=30),
            start_to_close_timeout=timedelta(seconds=15),
            retry_policy=INTERNAL_API_RETRY,
        )

        workflow.logger.info("Offer workflow completed: %s", data.offer_uuid)
        return OfferWorkflowResult(status="completed", offer_uuid=data.offer_uuid)
