# Internal module: service adapters for Content API vs Merchant API.
from __future__ import annotations

import os
import warnings
from typing import Any, Optional

from googleapiclient import discovery
from googleapiclient.errors import HttpError
from google.auth.exceptions import RefreshError

from .exception import (
    MctAccountLostAccessException,
    MerchantCenterServiceDownException,
    get_exception_message,
)


def _use_merchant_api_from_env() -> bool:
    return os.environ.get("USE_MERCHANT_API", "false").lower() in ("true", "1")


def get_mct_service(credentials: Any, use_merchant_api: Optional[bool] = None):
    """Return a service adapter (Content API or Merchant API) for the given credentials.

    Args:
        credentials: OAuth credentials (same scope for both backends).
        use_merchant_api: If True, force Merchant API; if False, force Content API.
            If None, use the USE_MERCHANT_API environment variable (default: Content API).
    """
    if use_merchant_api is not None:
        use_merchant = use_merchant_api
    else:
        use_merchant = _use_merchant_api_from_env()
    if use_merchant:
        return _MerchantApiAdapter(credentials)
    warnings.warn(
        "Content API for Shopping will be sunset on August 18, 2026. "
        "Migrate to Merchant API by setting use_merchant_api=True or USE_MERCHANT_API=true.",
        DeprecationWarning,
        stacklevel=2,
    )
    return _ContentApiAdapter(credentials)


class _ContentApiAdapter:
    """Adapter that uses Content API for Shopping v2.1 (legacy)."""

    def __init__(self, credentials: Any) -> None:
        self._service = discovery.build(
            "content", "v2.1", credentials=credentials, cache_discovery=False
        )

    def get_account_name(self, merchant_id: int, user_email: Optional[str] = None) -> str:
        try:
            request = self._service.accounts().get(
                merchantId=merchant_id, accountId=merchant_id
            )
            response = request.execute()
            return response["name"]
        except RefreshError as err:
            raise MctAccountLostAccessException(
                get_exception_message(merchant_id, user_email)
            ) from err
        except HttpError as err:
            if 400 <= err.resp.status < 500:
                raise MctAccountLostAccessException(
                    get_exception_message(merchant_id, user_email)
                ) from err
            raise MerchantCenterServiceDownException(
                f"The Merchant Center API does not respond. Thus, we cannot check if we can access your Merchant Center account with the id: {merchant_id}. Please try again later."
            ) from err

    def list_products(self, merchant_id: int, user_email: Optional[str] = None) -> dict:
        try:
            request = self._service.products().list(merchantId=merchant_id)
            return request.execute()
        except RefreshError as err:
            raise MctAccountLostAccessException(
                get_exception_message(merchant_id, user_email)
            ) from err
        except HttpError as err:
            if 400 <= err.resp.status < 500:
                raise MctAccountLostAccessException(
                    f"This merchant id ({merchant_id}) is for multi acccounts. You can only link sub-accounts."
                ) from err
            raise MerchantCenterServiceDownException(
                f"The Merchant Center API does not respond. Thus, we cannot check if we can access your Merchant Center account with the id: {merchant_id}. Please try again later."
            ) from err


class _MerchantApiAdapter:
    """Adapter that uses Merchant API client libraries (Accounts + Products)."""

    def __init__(self, credentials: Any) -> None:
        from google.shopping.merchant_accounts_v1 import (
            AccountsServiceClient,
            GetAccountRequest,
        )
        from google.shopping.merchant_products_v1 import (
            ListProductsRequest,
            ProductsServiceClient,
        )

        self._credentials = credentials
        self._accounts_client = AccountsServiceClient(credentials=credentials)
        self._products_client = ProductsServiceClient(credentials=credentials)
        self._GetAccountRequest = GetAccountRequest
        self._ListProductsRequest = ListProductsRequest

    def get_account_name(self, merchant_id: int, user_email: Optional[str] = None) -> str:
        import google.api_core.exceptions as gax_exceptions

        request = self._GetAccountRequest(name=f"accounts/{merchant_id}")
        try:
            account = self._accounts_client.get_account(request=request)
            return account.account_name or ""
        except gax_exceptions.PermissionDenied as err:
            raise MctAccountLostAccessException(
                get_exception_message(merchant_id, user_email)
            ) from err
        except gax_exceptions.NotFound as err:
            raise MctAccountLostAccessException(
                get_exception_message(merchant_id, user_email)
            ) from err
        except (gax_exceptions.InternalServerError, gax_exceptions.ServiceUnavailable) as e:
            raise MerchantCenterServiceDownException(
                f"The Merchant Center API does not respond. Thus, we cannot check if we can access your Merchant Center account with the id: {merchant_id}. Please try again later."
            ) from e

    def list_products(self, merchant_id: int, user_email: Optional[str] = None) -> dict:
        import google.api_core.exceptions as gax_exceptions

        request = self._ListProductsRequest(parent=f"accounts/{merchant_id}")
        try:
            response = self._products_client.list_products(request=request)
            products_list = list(response.products)
            return {
                "products": products_list,
                "resources": products_list,
                "nextPageToken": response.next_page_token or "",
            }
        except gax_exceptions.PermissionDenied as err:
            raise MctAccountLostAccessException(
                f"This merchant id ({merchant_id}) is for multi acccounts. You can only link sub-accounts."
            ) from err
        except gax_exceptions.NotFound:
            raise MctAccountLostAccessException(
                f"This merchant id ({merchant_id}) is for multi acccounts. You can only link sub-accounts."
            ) from err
        except (gax_exceptions.InternalServerError, gax_exceptions.ServiceUnavailable) as e:
            raise MerchantCenterServiceDownException(
                f"The Merchant Center API does not respond. Thus, we cannot check if we can access your Merchant Center account with the id: {merchant_id}. Please try again later."
            ) from e
