"""
KYC Application Workflow.

This workflow handles the KYC verification process:
1. Create KYC record in Odoo ERP
2. Wait for approval or rejection signal
3. On approval: create organization in Logto

NOTE: This workflow is pure business logic. It doesn't know
about service URLs (Odoo, Teams, Logto). Activities are
executed by the platform worker which has the configuration.
"""

from datetime import timedelta

from temporalio import workflow
from temporalio.common import RetryPolicy

with workflow.unsafe.imports_passed_through():
    from ..types import (
        CreateLogtoOrgInput,
        CreateLogtoOrgResult,
        CreateTeamInput,
        CreateTeamResult,
        LogKycEventInput,
        KycApprovalData,
        KycData,
        KycRejectionData,
        KycWorkflowResult,
        SetBuyerLogtoOrgInput,
        SetLogtoOrgIdInput,
    )


# Retry policy for external API calls
EXTERNAL_API_RETRY = RetryPolicy(
    maximum_attempts=5,
    initial_interval=timedelta(seconds=2),
    backoff_coefficient=2.0,
    maximum_interval=timedelta(seconds=30),
)

# Retry policy for internal service calls
INTERNAL_API_RETRY = RetryPolicy(
    maximum_attempts=3,
    initial_interval=timedelta(seconds=1),
    backoff_coefficient=2.0,
    maximum_interval=timedelta(seconds=10),
)


@workflow.defn(name="kyc_application")
class KycApplicationWorkflow:
    """
    KYC Workflow with signals for approval/rejection.

    Uses typed dataclasses for all activity inputs/outputs for better
    type safety and IDE support.
    """

    def __init__(self) -> None:
        self._approved = False
        self._rejected = False
        self._approval_data: KycApprovalData | None = None
        self._rejection_data: KycRejectionData | None = None

    @workflow.signal
    async def approve_kyc(self, data: KycApprovalData) -> None:
        """Signal to approve the KYC request."""
        workflow.logger.info("KYC approval signal received from %s", data.approved_by)
        self._approved = True
        self._approval_data = data

    @workflow.signal
    async def reject_kyc(self, data: KycRejectionData) -> None:
        """Signal to reject the KYC request."""
        workflow.logger.info(
            "KYC rejection signal received from %s: %s",
            data.rejected_by,
            data.reason,
        )
        self._rejected = True
        self._rejection_data = data

    @workflow.run
    async def run(self, kyc_data: KycData) -> KycWorkflowResult:
        """Execute the KYC workflow."""
        workflow.logger.info(
            "Starting KYC workflow for request %s (team_name=%s)",
            kyc_data.kyc_request_id,
            kyc_data.team_name,
        )

        await self._log_status_event(kyc_data, "submitted", "Заявка отправлена")

        # Step 1: Add KYC to Odoo ERP
        await workflow.execute_activity(
            "add_kyc_to_odoo",
            kyc_data,
            schedule_to_close_timeout=timedelta(seconds=60),
            start_to_close_timeout=timedelta(seconds=30),
            retry_policy=EXTERNAL_API_RETRY,
        )

        await self._log_status_event(kyc_data, "in_review", "Заявка на проверке")

        workflow.logger.info("Waiting for approval/rejection signal...")

        # Step 2: Wait for approval or rejection signal
        await workflow.wait_condition(lambda: self._approved or self._rejected)

        if self._rejected:
            return await self._handle_rejection(kyc_data)

        return await self._handle_approval(kyc_data)

    async def _log_status_event(self, kyc_data: KycData, event: str, description: str) -> None:
        """Best-effort logging of user-facing KYC status events."""
        try:
            await workflow.execute_activity(
                "log_kyc_event",
                LogKycEventInput(
                    kyc_id=kyc_data.kyc_request_id,
                    user_id=kyc_data.owner_id,
                    event=event,
                    description=description,
                ),
                schedule_to_close_timeout=timedelta(seconds=10),
                start_to_close_timeout=timedelta(seconds=5),
                retry_policy=INTERNAL_API_RETRY,
            )
        except Exception as exc:
            workflow.logger.warning("Failed to log KYC event %s: %s", event, exc)

    async def _handle_rejection(self, kyc_data: KycData) -> KycWorkflowResult:
        """Handle KYC rejection."""
        reason = self._rejection_data.reason if self._rejection_data else ""

        workflow.logger.info(
            "KYC rejected for %s: %s",
            kyc_data.team_name,
            reason,
        )

        await self._log_status_event(kyc_data, "rejected", "Заявка отклонена")

        return KycWorkflowResult(
            status="rejected",
            kyc_request_id=kyc_data.kyc_request_id,
            reason=reason,
        )

    async def _handle_approval(self, kyc_data: KycData) -> KycWorkflowResult:
        """Handle KYC approval."""
        workflow.logger.info("KYC approved for %s", kyc_data.team_name)

        await self._log_status_event(kyc_data, "approved", "Заявка одобрена")

        # Step 3: Create Team in Teams service
        team_result: CreateTeamResult = await workflow.execute_activity(
            "create_team_in_teams",
            CreateTeamInput(
                team_name=kyc_data.team_name,
                owner_id=kyc_data.owner_id,
                team_type="BUYER",
                country_code=kyc_data.country_code,
            ),
            schedule_to_close_timeout=timedelta(seconds=60),
            start_to_close_timeout=timedelta(seconds=30),
            retry_policy=INTERNAL_API_RETRY,
        )

        # Handle both dict (replay) and dataclass result
        team_uuid = (
            team_result.team_uuid
            if hasattr(team_result, "team_uuid")
            else team_result["team_uuid"]
        )

        workflow.logger.info("Team created: %s", team_uuid)

        # Step 4: Create organization in Logto
        org_result: CreateLogtoOrgResult = await workflow.execute_activity(
            "create_logto_org",
            CreateLogtoOrgInput(
                team_id=team_uuid,
                team_name=kyc_data.team_name,
                owner_id=kyc_data.owner_id,
            ),
            schedule_to_close_timeout=timedelta(seconds=60),
            start_to_close_timeout=timedelta(seconds=30),
            retry_policy=EXTERNAL_API_RETRY,
        )

        # Handle both dict (replay) and dataclass result
        org_id = (
            org_result.organization_id
            if hasattr(org_result, "organization_id")
            else org_result["organization_id"]
        )

        # Step 5: Set Logto org ID on buyer in Odoo
        await workflow.execute_activity(
            "set_buyer_logto_org",
            SetBuyerLogtoOrgInput(
                team_uuid=team_uuid,
                logto_org_id=org_id,
            ),
            schedule_to_close_timeout=timedelta(seconds=30),
            start_to_close_timeout=timedelta(seconds=15),
            retry_policy=EXTERNAL_API_RETRY,
        )

        # Step 6: Set Logto org ID in Teams
        await workflow.execute_activity(
            "set_logto_org_id",
            SetLogtoOrgIdInput(
                team_id=team_uuid,
                logto_org_id=org_id,
            ),
            schedule_to_close_timeout=timedelta(seconds=30),
            start_to_close_timeout=timedelta(seconds=15),
            retry_policy=INTERNAL_API_RETRY,
        )

        workflow.logger.info(
            "KYC workflow completed: team %s logto_org=%s",
            team_uuid,
            org_id,
        )

        return KycWorkflowResult(
            status="approved",
            kyc_request_id=kyc_data.kyc_request_id,
            team_id=team_uuid,
            logto_org_id=org_id,
        )
