"""Magento domain ports (protocols) - dependency inversion."""

from __future__ import annotations

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


class MagentoApiClient(Protocol):
    """External Magento REST API - implement with OAuth1 HTTP adapter."""

    def get_product(self, sku: str) -> Optional[Dict[str, Any]]:
        """GET /V1/products/{sku}. Returns None if 404."""
        ...

    def create_product(self, payload: Dict[str, Any]) -> Dict[str, Any]:
        """POST /V1/products. Returns response body."""
        ...

    def update_product(self, sku: str, payload: Dict[str, Any]) -> Dict[str, Any]:
        """PUT /V1/products/{sku}. Returns response body."""
        ...

    def verify_connection(self) -> bool:
        """Lightweight call to verify tokens work (e.g. GET /V1/store/storeViews)."""
        ...

    # --- Product upsert (low-level for 404 detection) ---

    def put_product(
        self, sku: str, payload: Dict[str, Any]
    ) -> Tuple[int, Optional[Dict[str, Any]]]:
        """PUT /V1/products/{sku}. Returns (status, body)."""
        ...

    def post_product(
        self, payload: Dict[str, Any]
    ) -> Tuple[int, Optional[Dict[str, Any]]]:
        """POST /V1/products. Returns (status, body)."""
        ...

    # --- Async bulk product upserts ---

    def put_products_bulk_async(
        self, products: List[Dict[str, Any]]
    ) -> Tuple[int, Optional[Dict[str, Any]], Optional[str]]:
        """PUT /async/bulk/V1/products/bySku. Returns (status, body, error)."""
        ...

    def post_products_bulk_async(
        self, products: List[Dict[str, Any]]
    ) -> Tuple[int, Optional[Dict[str, Any]], Optional[str]]:
        """POST /async/bulk/V1/products. Returns (status, body, error)."""
        ...

    def get_bulk_status(
        self, bulk_uuid: str
    ) -> Tuple[int, Optional[Dict[str, Any]], Optional[str]]:
        """GET /V1/bulk/{bulkUuid}/status."""
        ...

    def get_bulk_detailed_status(
        self, bulk_uuid: str
    ) -> Tuple[int, Optional[Dict[str, Any]], Optional[str]]:
        """GET /V1/bulk/{bulkUuid}/detailed-status."""
        ...

    # --- Media (base64 upload) ---

    def get_product_media(self, sku: str) -> Tuple[int, List[Dict[str, Any]], Optional[str]]:
        """GET /V1/products/{sku}/media. Returns (status, entries, error)."""
        ...

    def post_product_media(
        self, sku: str, entry: Dict[str, Any]
    ) -> Tuple[int, Optional[Dict[str, Any]], Optional[str]]:
        """POST /V1/products/{sku}/media with base64 content. Returns (status, body, error)."""
        ...

    def delete_product_media(
        self, sku: str, entry_id: int
    ) -> Tuple[int, Optional[str]]:
        """DELETE /V1/products/{sku}/media/{entryId}. Returns (status, error)."""
        ...

    # --- Configurable relations ---

    def get_configurable_options(
        self, sku: str
    ) -> Tuple[int, List[Dict[str, Any]], Optional[str]]:
        """GET /V1/configurable-products/{sku}/options/all. Returns (status, options, error)."""
        ...

    def get_configurable_children(
        self, sku: str
    ) -> Tuple[int, List[str], Optional[str]]:
        """GET /V1/configurable-products/{sku}/children. Returns (status, child_skus, error)."""
        ...

    def add_configurable_child(
        self, parent_sku: str, child_sku: str
    ) -> Tuple[int, Optional[str]]:
        """POST /V1/configurable-products/{sku}/child. Returns (status, error)."""
        ...

    def create_configurable_option(
        self, parent_sku: str, payload: Dict[str, Any]
    ) -> Tuple[int, Optional[Dict[str, Any]]]:
        """POST /V1/configurable-products/{sku}/options. Returns (status, body)."""
        ...

    # --- Attribute sets ---

    def list_attribute_sets(
        self, *, page_size: int = 100, current_page: int = 1
    ) -> Tuple[int, List[Dict[str, Any]], Optional[str]]:
        """GET /V1/products/attribute-sets/sets/list."""
        ...

    def get_attributes_for_set(
        self, attribute_set_id: int
    ) -> Tuple[int, List[Dict[str, Any]], Optional[str]]:
        """GET /V1/products/attribute-sets/{id}/attributes."""
        ...

    def get_attribute_id_by_code(self, attribute_code: str) -> Optional[int]:
        """GET /V1/products/attributes/{code}. Returns attribute_id or None if not found."""
        ...

    def get_attribute_detail(
        self, attribute_code: str
    ) -> Tuple[int, Optional[Dict[str, Any]]]:
        """
        GET /V1/products/attributes/{code}.
        Returns (status, body). body has attribute_id, frontend_label, etc.
        """
        ...

    def get_attribute_options(
        self, attribute_code: str
    ) -> Tuple[int, List[Dict[str, Any]]]:
        """
        GET /V1/products/attributes/{code}/options.
        Returns (status, options). options: [{"label": "X", "value": "123"}, ...].
        value is value_index for Magento option creation.
        """
        ...

    def find_attribute_by_frontend_label(
        self, label: str
    ) -> Tuple[int, Optional[Dict[str, Any]]]:
        """
        GET /V1/products/attributes with searchCriteria by frontend_label.
        Returns (status, best_match_dict). Best match = case-insensitive equals.
        """
        ...

    def remove_configurable_child(
        self, parent_sku: str, child_sku: str
    ) -> Tuple[int, Optional[str]]:
        """DELETE /V1/configurable-products/{parentSku}/children/{childSku}."""
        ...

    # --- Store info ---

    def get_store_websites(self) -> Tuple[int, List[Dict[str, Any]]]:
        """GET /V1/store/websites."""
        ...

    def get_store_views(self) -> Tuple[int, List[Dict[str, Any]]]:
        """GET /V1/store/storeViews."""
        ...

    def get_store_groups(self) -> Tuple[int, List[Dict[str, Any]]]:
        """GET /V1/store/storeGroups."""
        ...

    # --- Categories ---

    def get_categories_tree(self) -> Tuple[int, Optional[Dict[str, Any]]]:
        """GET /V1/categories. Returns (status, tree_dict)."""
        ...

    def create_category(
        self, payload: Dict[str, Any]
    ) -> Tuple[int, Optional[Dict[str, Any]]]:
        """POST /V1/categories. Returns (status, body)."""
        ...

    # --- Media update ---

    def update_product_media(
        self, sku: str, entry_id: int, entry: Dict[str, Any]
    ) -> Tuple[int, Optional[Dict[str, Any]], Optional[str]]:
        """PUT /V1/products/{sku}/media/{entryId}. Returns (status, body, error)."""
        ...
