"""Production composition for authenticated Agent result callbacks."""

from __future__ import annotations

import os
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Callable, Optional

from arr_ingestion.postgres import DatabaseConfig, PostgresIngestionRepository
from arr_ingestion.service import IngestionService
from arr_ingestion.validation import DeliveryValidator, ProcessorPolicy
from arr_processing.callbacks import AgentResultWriteback
from arr_processing.config import ResultVerificationConfig
from arr_processing.errors import ProcessingTransportError
from arr_processing.postgres import PostgresProcessingState, ProcessingDatabaseConfig
from arr_processing.registration import ProcessingOutputRegistrar, RemoteFilePort
from arr_processing.remote_files import PrefixRemoteFilePort
from arr_processing.runner import ProcessingRunner, RemoteRunSnapshot
from arr_processing.policy import load_legacy_direct_processor_policy as load_processor_policy
from arr_storage.aliyun_oss_v2 import AliyunOssConfig, AliyunOssV2Client
from arr_storage.contracts import ObjectKeyPolicy
from arr_storage.exchange import OutputExchangeConfig
from arr_storage.remote import CloudObjectBackend
from arr_storage.store import ManagedObjectStore
from arr_web.legacy_agent_services import ProcessingAgentResultCoordinator


class CallbackOnlyTransport:
    """Callbacks do not require remote Agent network authority in this process."""

    @staticmethod
    def _disabled() -> None:
        raise ProcessingTransportError(
            "PROCESSING_REMOTE_DISABLED",
            retryable=False,
        )

    def submit(self, request: Any, idempotency_key: str) -> RemoteRunSnapshot:
        del request, idempotency_key
        self._disabled()

    def get(self, request: Any, remote_run_id: str) -> RemoteRunSnapshot:
        del request, remote_run_id
        self._disabled()

    def cancel(self, request: Any, remote_run_id: str) -> RemoteRunSnapshot:
        del request, remote_run_id
        self._disabled()


@dataclass
class AgentWritebackRuntime:
    coordinator: ProcessingAgentResultCoordinator
    close_callback: Optional[Callable[[], None]] = None

    def close(self) -> None:
        if self.close_callback is not None:
            self.close_callback()


def compose_agent_writeback(
    *,
    object_store: ManagedObjectStore,
    remote_files: RemoteFilePort,
    processor_policy: ProcessorPolicy,
    verification: ResultVerificationConfig,
    connect: Optional[Callable[[str], Any]] = None,
) -> AgentWritebackRuntime:
    processing_config = (
        ProcessingDatabaseConfig("controlled")
        if connect is not None
        else ProcessingDatabaseConfig.from_environment()
    )
    ingestion_config = (
        DatabaseConfig("controlled")
        if connect is not None
        else DatabaseConfig.from_environment()
    )
    state = PostgresProcessingState(processing_config, connect=connect)
    runner = ProcessingRunner(
        CallbackOnlyTransport(),
        state,
        verification.verifier(),
    )
    repository = PostgresIngestionRepository(ingestion_config, connect=connect)
    writeback = AgentResultWriteback(
        runner,
        state,
        ProcessingOutputRegistrar(remote_files, object_store),
        IngestionService(
            DeliveryValidator(object_store, processor_policy),
            repository,
        ),
        outcome_resolver=state,
    )
    return AgentWritebackRuntime(ProcessingAgentResultCoordinator(writeback))


def compose_oss_agent_writeback(
    *,
    project_root: Path,
    connect: Optional[Callable[[str], Any]] = None,
) -> AgentWritebackRuntime:
    oss_client = AliyunOssV2Client(AliyunOssConfig.from_environment())
    try:
        oss_client.assert_immutable_writes_supported()
        key_policy = ObjectKeyPolicy(os.environ.get("ARR_OBJECT_PREFIX", "arr"))
        object_store = ManagedObjectStore(
            CloudObjectBackend(oss_client),
            key_policy,
        )
        runtime = compose_agent_writeback(
            object_store=object_store,
            remote_files=PrefixRemoteFilePort(
                oss_client,
                OutputExchangeConfig.from_environment(),
            ),
            processor_policy=load_processor_policy(project_root),
            verification=ResultVerificationConfig.from_environment(),
            connect=connect,
        )
        runtime.close_callback = oss_client.close
        return runtime
    except Exception:
        try:
            oss_client.close()
        except Exception:
            pass
        raise
