from __future__ import annotations

import json

from pytest_httpx import HTTPXMock

from ebay_client.account.client import AccountClient
from ebay_client.core.auth.models import OAuthToken
from ebay_client.core.http.transport import ApiTransport
from ebay_client.feed.client import FeedClient
from ebay_client.fulfillment.client import FulfillmentClient
from ebay_client.generated.account.models import Programs
from ebay_client.generated.feed.models import TaskCollection
from ebay_client.generated.fulfillment.models import Order
from ebay_client.generated.inventory.models import InventoryItemWithSkuLocaleGroupid
from ebay_client.generated.notification.models import (
    Config,
    CreateSubscriptionFilterRequest,
    CreateSubscriptionRequest,
    DeliveryConfig,
    Subscription,
    SubscriptionFilter,
    SubscriptionPayloadDetail,
    DestinationRequest,
    TopicSearchResponse,
    UpdateSubscriptionRequest,
)
from ebay_client.inventory.client import InventoryClient
from ebay_client.notification.client import NotificationClient


class DummyOAuthClient:
    def get_valid_token(self, *, scopes: list[str] | None = None) -> OAuthToken:
        return OAuthToken(access_token="test-token", scope=" ".join(scopes or []))


def build_transport() -> ApiTransport:
    return ApiTransport(base_url="https://api.ebay.com", oauth_client=DummyOAuthClient())


def test_notification_wrapper_returns_pydantic_model(httpx_mock: HTTPXMock) -> None:
    httpx_mock.add_response(
        method="GET",
        url="https://api.ebay.com/commerce/notification/v1/topic?limit=10",
        json={"topics": [{"topicId": "MARKETPLACE_ACCOUNT_DELETION", "description": "topic"}], "total": 1},
    )

    client = NotificationClient(build_transport())
    result = client.get_topics(limit=10)

    assert isinstance(result, TopicSearchResponse)
    assert result.total == 1
    assert result.topics and result.topics[0].topicId == "MARKETPLACE_ACCOUNT_DELETION"
    request = httpx_mock.get_requests()[0]
    assert request.headers["Authorization"] == "Bearer test-token"


def test_notification_wrapper_serializes_typed_request_model(httpx_mock: HTTPXMock) -> None:
    httpx_mock.add_response(
        method="POST",
        url="https://api.ebay.com/commerce/notification/v1/destination",
        json={},
        status_code=201,
    )

    client = NotificationClient(build_transport())
    payload = DestinationRequest(
        name="main-destination",
        status="ENABLED",
        deliveryConfig=DeliveryConfig(
            endpoint="https://example.test/webhook",
            verificationToken="verification_token_1234567890123456",
        ),
    )

    client.create_destination(payload)

    request = httpx_mock.get_requests()[0]
    body = json.loads(request.content.decode("utf-8"))
    assert body["name"] == "main-destination"
    assert body["deliveryConfig"]["endpoint"] == "https://example.test/webhook"


def test_notification_config_wrapper_round_trip(httpx_mock: HTTPXMock) -> None:
    httpx_mock.add_response(
        method="GET",
        url="https://api.ebay.com/commerce/notification/v1/config",
        json={"alertEmail": "alerts@example.test"},
    )
    httpx_mock.add_response(
        method="PUT",
        url="https://api.ebay.com/commerce/notification/v1/config",
        status_code=204,
    )

    client = NotificationClient(build_transport())
    config = client.get_config()
    client.update_config(Config(alertEmail="ops@example.test"))

    assert isinstance(config, Config)
    assert config.alertEmail == "alerts@example.test"
    request = httpx_mock.get_requests()[1]
    body = json.loads(request.content.decode("utf-8"))
    assert body["alertEmail"] == "ops@example.test"


def test_notification_subscription_wrapper_serializes_and_returns_models(httpx_mock: HTTPXMock) -> None:
    httpx_mock.add_response(
        method="POST",
        url="https://api.ebay.com/commerce/notification/v1/subscription",
        json={},
        status_code=201,
    )
    httpx_mock.add_response(
        method="GET",
        url="https://api.ebay.com/commerce/notification/v1/subscription/SUB-1",
        json={"subscriptionId": "SUB-1", "topicId": "TOPIC-1", "status": "ENABLED"},
    )
    httpx_mock.add_response(
        method="PUT",
        url="https://api.ebay.com/commerce/notification/v1/subscription/SUB-1",
        status_code=204,
    )
    httpx_mock.add_response(
        method="POST",
        url="https://api.ebay.com/commerce/notification/v1/subscription/SUB-1/enable",
        status_code=204,
    )
    httpx_mock.add_response(
        method="POST",
        url="https://api.ebay.com/commerce/notification/v1/subscription/SUB-1/test",
        status_code=202,
    )

    client = NotificationClient(build_transport())
    create_payload = CreateSubscriptionRequest(
        destinationId="DEST-1",
        topicId="TOPIC-1",
        status="DISABLED",
        payload=SubscriptionPayloadDetail(
            deliveryProtocol="HTTPS",
            format="JSON",
            schemaVersion="1.0",
        ),
    )
    update_payload = UpdateSubscriptionRequest(status="ENABLED", destinationId="DEST-1")

    client.create_subscription(create_payload)
    subscription = client.get_subscription("SUB-1")
    client.update_subscription("SUB-1", update_payload)
    client.enable_subscription("SUB-1")
    client.test_subscription("SUB-1")

    assert isinstance(subscription, Subscription)
    assert subscription.subscriptionId == "SUB-1"
    create_request = httpx_mock.get_requests()[0]
    create_body = json.loads(create_request.content.decode("utf-8"))
    assert create_body["destinationId"] == "DEST-1"
    assert create_body["payload"]["deliveryProtocol"] == "HTTPS"
    update_request = httpx_mock.get_requests()[2]
    update_body = json.loads(update_request.content.decode("utf-8"))
    assert update_body == {"destinationId": "DEST-1", "status": "ENABLED"}


def test_notification_subscription_filter_wrapper_serializes_and_returns_model(httpx_mock: HTTPXMock) -> None:
    httpx_mock.add_response(
        method="POST",
        url="https://api.ebay.com/commerce/notification/v1/subscription/SUB-1/filter",
        json={},
        status_code=201,
    )
    httpx_mock.add_response(
        method="GET",
        url="https://api.ebay.com/commerce/notification/v1/subscription/SUB-1/filter/FILTER-1",
        json={"filterId": "FILTER-1", "subscriptionId": "SUB-1", "filterStatus": "ENABLED"},
    )
    httpx_mock.add_response(
        method="DELETE",
        url="https://api.ebay.com/commerce/notification/v1/subscription/SUB-1/filter/FILTER-1",
        status_code=204,
    )

    client = NotificationClient(build_transport())
    payload = CreateSubscriptionFilterRequest(
        filterSchema={
            "properties": {
                "data": {
                    "type": "object",
                }
            }
        }
    )

    client.create_subscription_filter("SUB-1", payload)
    subscription_filter = client.get_subscription_filter("SUB-1", "FILTER-1")
    client.delete_subscription_filter("SUB-1", "FILTER-1")

    assert isinstance(subscription_filter, SubscriptionFilter)
    assert subscription_filter.filterId == "FILTER-1"
    request = httpx_mock.get_requests()[0]
    body = json.loads(request.content.decode("utf-8"))
    assert body["filterSchema"]["properties"]["data"]["type"] == "object"


def test_inventory_wrapper_returns_inventory_item_model(httpx_mock: HTTPXMock) -> None:
    httpx_mock.add_response(
        method="GET",
        url="https://api.ebay.com/sell/inventory/v1/inventory_item/SKU-1",
        json={"sku": "SKU-1"},
    )

    client = InventoryClient(build_transport())
    result = client.get_inventory_item("SKU-1")

    assert isinstance(result, InventoryItemWithSkuLocaleGroupid)
    assert result.sku == "SKU-1"


def test_fulfillment_wrapper_returns_order_model(httpx_mock: HTTPXMock) -> None:
    httpx_mock.add_response(
        method="GET",
        url="https://api.ebay.com/sell/fulfillment/v1/order/ORDER-1",
        json={"orderId": "ORDER-1"},
    )

    client = FulfillmentClient(build_transport())
    result = client.get_order("ORDER-1")

    assert isinstance(result, Order)
    assert result.orderId == "ORDER-1"


def test_account_wrapper_returns_programs_model(httpx_mock: HTTPXMock) -> None:
    httpx_mock.add_response(
        method="GET",
        url="https://api.ebay.com/sell/account/v1/program/get_opted_in_programs",
        json={"programs": [{"programType": "OUT_OF_STOCK_CONTROL"}]},
    )

    client = AccountClient(build_transport())
    result = client.get_opted_in_programs()

    assert isinstance(result, Programs)
    assert result.programs and result.programs[0].programType == "OUT_OF_STOCK_CONTROL"


def test_feed_wrapper_returns_task_collection_model(httpx_mock: HTTPXMock) -> None:
    httpx_mock.add_response(
        method="GET",
        url="https://api.ebay.com/sell/feed/v1/task?feed_type=LMS_ORDER_REPORT",
        json={"tasks": [{"taskId": "TASK-1"}], "total": 1},
    )

    client = FeedClient(build_transport())
    result = client.get_tasks(feed_type="LMS_ORDER_REPORT")

    assert isinstance(result, TaskCollection)
    assert result.total == 1
    assert result.tasks and result.tasks[0].taskId == "TASK-1"