from injector import inject

from ..strategies.factories import IntegrationSourceToTargetExecuteStrategyFactory
from ...base import IntegrationAdapter
from ....domain.base import IntegrationBase
from .....connection.factories import ConnectionTargetAdapterFactory
from .....domain.enums.events import EVENT_EXECUTION_INTEGRATION_EXECUTE_TRUNCATE, \
    EVENT_EXECUTION_INTEGRATION_EXECUTE_SOURCE, EVENT_LOG
from .....operation.domain import OperationIntegrationBase
from .....pubsub.base import ChannelQueue
from .....pubsub.domain import TaskMessage
from .....pubsub.publisher import Publisher
from ......dependency import IScoped


class SourceToTargetIntegration(IntegrationAdapter, IScoped):
    @inject
    def __init__(self,
                 integration_execute_strategy_factory: IntegrationSourceToTargetExecuteStrategyFactory,
                 connection_target_adapter_factory: ConnectionTargetAdapterFactory
                 ):
        self.connection_target_adapter_factory = connection_target_adapter_factory
        self.integration_execute_strategy_factory = integration_execute_strategy_factory

    def execute(
            self,
            operation_integration: OperationIntegrationBase,
            channel: ChannelQueue
    ) -> int:
        publisher = Publisher(channel=channel)
        target_adapter = self.connection_target_adapter_factory.get_adapter(
            connection_type=operation_integration.Integration.TargetConnections.ConnectionType
        )
        if operation_integration.Integration.IsTargetTruncate:
            truncate_affected_row_count = target_adapter.clear_data(
                integration=operation_integration.Integration
            )
            publisher.publish(
                message=TaskMessage(
                    event=EVENT_EXECUTION_INTEGRATION_EXECUTE_TRUNCATE,
                    kwargs={
                        "data": operation_integration,
                        "row_count": truncate_affected_row_count
                    }
                )
            )
        order = operation_integration.Order
        process_count = operation_integration.ProcessCount
        limit = operation_integration.Limit
        execute_integration_strategy = self.integration_execute_strategy_factory.get(
            process_count=process_count
        )
        strategy_name = type(execute_integration_strategy).__name__
        publisher.publish(
            message=TaskMessage(
                event=EVENT_LOG,
                kwargs={
                    'data': operation_integration,
                    'message': f"{order} - integration will execute on {strategy_name}. {process_count}-{limit}"
                }
            )
        )
        affected_row_count = execute_integration_strategy.execute(
            operation_integration=operation_integration,
            channel=channel
        )
        publisher.publish(
            message=TaskMessage(
                event=EVENT_EXECUTION_INTEGRATION_EXECUTE_SOURCE,
                kwargs={
                    "data": operation_integration,
                    "row_count": affected_row_count
                }
            )
        )
        return affected_row_count

    def get_start_message(self, integration: IntegrationBase):
        message = f"Integration execute started."
        if integration.TargetConnections.Sql is not None:
            message = f"{integration.TargetConnections.Sql.Schema}.{integration.TargetConnections.Sql.ObjectName} integration execute started."
        elif integration.TargetConnections.BigData is not None:
            message = f"{integration.TargetConnections.BigData.Schema}.{integration.TargetConnections.BigData.ObjectName} integration execute started."
        elif integration.TargetConnections.WebService is not None:
            message = f"{integration.TargetConnections.WebService.Method} integration execute started."
        elif integration.TargetConnections.File is not None:
            message = f"{integration.TargetConnections.File.Folder}\\{integration.TargetConnections.File.FileName} integration execute started."
        elif integration.TargetConnections.Queue is not None:
            message = f"{integration.TargetConnections.Queue.TopicName} integration execute started."
        return message

    def get_finish_message(self, integration: IntegrationBase, data_count: int):
        message = f"Integration execute finished"
        if integration.TargetConnections.Sql is not None:
            message = f"{integration.TargetConnections.Sql.Schema}.{integration.TargetConnections.Sql.ObjectName} integration execute finished."
        elif integration.TargetConnections.BigData is not None:
            message = f"{integration.TargetConnections.BigData.Schema}.{integration.TargetConnections.BigData.ObjectName} integration execute finished."
        elif integration.TargetConnections.BigData is not None:
            message = f"{integration.TargetConnections.WebService.Method} integration execute finished."
        elif integration.TargetConnections.File is not None:
            message = f"{integration.TargetConnections.File.Folder}\\{integration.TargetConnections.File.FileName} integration execute finished."
        elif integration.TargetConnections.Queue is not None:
            message = f"{integration.TargetConnections.Queue.TopicName} integration execute finished."

        return message

    def get_error_message(self, integration: IntegrationBase):
        message = f"Integration execute getting error."
        if integration.TargetConnections.Sql is not None:
            message = f"{integration.TargetConnections.Sql.Schema}.{integration.TargetConnections.Sql.ObjectName} integration execute getting error."
        elif integration.TargetConnections.BigData is not None:
            message = f"{integration.TargetConnections.BigData.Schema}.{integration.TargetConnections.BigData.ObjectName} integration execute getting error."
        if integration.TargetConnections.WebService is not None:
            message = f"{integration.TargetConnections.WebService.Method} integration execute getting error."
        elif integration.TargetConnections.File is not None:
            message = f"{integration.TargetConnections.File.Folder}\\{integration.TargetConnections.File.FileName} integration execute getting error."
        elif integration.TargetConnections.Queue is not None:
            message = f"{integration.TargetConnections.Queue.TopicName} integration execute getting error."
        return message
