"""Task type for exporting data."""

from __future__ import annotations

from typing import Any, Dict, List, Tuple, Optional, TYPE_CHECKING

from ..connection import Connection

from ..task import Task
from ..datastar_api import DatastarAPI

if TYPE_CHECKING:
    from ..macro import Macro


class ExportTask(Task):
    """Exports project data to an external destination."""

    def __init__(
        self,
        macro: "Macro",
        *,
        name: str = "",
        description: str = "",
        source_connection: Connection,
        destination_connection: Optional[Connection] = None,
        source_table: str = "",
        destination_table: str = "",
        destination_table_type: str = "new",
        destination_table_action: str = "replace",
        condition: str = "",
        mappings: List[Tuple[str, str]] = [],
        file_name: str = "",
        auto_join: bool = True,
        previous_task: Optional[Task] = None,
        persist: bool = True,
    ):
        self._source_connection_id = source_connection._id
        if destination_connection is not None:
            self._destination_connection_id = destination_connection._id
        else:
            self._destination_connection_id = ""

        self.source_table = source_table
        self.destination_table = destination_table
        self.destination_table_type = destination_table_type or "new"
        self.destination_table_action = destination_table_action or "replace"
        self.condition = condition
        self.mappings = mappings or []
        self.file_name = file_name

        # Note: base will persist, which calls back into subclass, so call init here at end
        super().__init__(
            macro=macro,
            name=name,
            description=description,
            auto_join=auto_join,
            previous_task=previous_task,
            persist=persist,
        )

    # ------------------------------------------------------------------
    # Abstract method implementation

    def _get_task_type(self) -> str:
        return "export"

    def _to_configuration(self) -> Dict[str, Any]:

        configuration: Dict[str, Any] = {}

        # Add source connection
        configuration["source"] = {
            "connectorId": self._source_connection_id,
            "table": str(self.source_table),
        }

        # Add destination (file or connection)
        if self._destination_connection_id:
            configuration["destination"] = {
                "type": "connector",
                "connectorId": self._destination_connection_id,
                "tableAction": self.destination_table_action,
                "tableType": self.destination_table_type,
            }
            if self.destination_table_type == "new":
                configuration["destination"]["newTableName"] = self.destination_table
            else:
                configuration["destination"]["table"] = self.destination_table
        else:
            configuration["destination"] = {"type": "file", "fileName": self.file_name}

        if self.condition:
            configuration["condition"] = self.condition

        configuration["mappings"] = self.mappings

        return configuration

    def _from_configuration(self, configuration: Dict[str, Any]) -> None:

        source_section = configuration["source"]
        destination_section = configuration["destination"]

        self._source_connection_id = source_section.get("connectorId")
        self.source_table = source_section.get("table")

        dest_type = destination_section.get("type", "connector")
        if dest_type == "file":
            # File mode
            self.file_name = destination_section.get("fileName") or ""
            self._destination_connection_id = ""
            self.destination_table = ""
            self.destination_table_type = ""
            self.destination_table_action = ""
        else:
            # Connector mode
            self.file_name = ""
            self._destination_connection_id = (
                destination_section.get("connectorId") or ""
            )
            self.destination_table = (
                destination_section.get("newTableName")
                or destination_section.get("table")
                or ""
            )
            self.destination_table_type = destination_section.get("tableType") or ""
            self.destination_table_action = destination_section.get("tableAction") or ""

        self.condition = configuration.get("condition")

        self.mappings = configuration.get("mappings") or []

    # ------------------------------------------------------------------
    # Connection properties (uncached)

    @property
    def source_connection(self) -> Connection:
        if self._source_connection_id == DatastarAPI.SANDBOX_CONNECTOR_ID:
            return self.macro.project.get_sandbox()
        return Connection._read_by_id(self._source_connection_id)

    @source_connection.setter
    def source_connection(self, value: Connection) -> None:
        self._source_connection_id = value._id

    @property
    def destination_connection(self) -> Optional[Connection]:
        if not self._destination_connection_id:
            return None
        if self._destination_connection_id == DatastarAPI.SANDBOX_CONNECTOR_ID:
            return self.macro.project.get_sandbox()
        return Connection._read_by_id(self._destination_connection_id)

    @destination_connection.setter
    def destination_connection(self, value: Optional[Connection]) -> None:
        self._destination_connection_id = value._id if value is not None else ""
