# tests/integration/api/v1/test_marketplace_products_endpoints.py
import pytest


@pytest.mark.integration
@pytest.mark.api
@pytest.mark.products
class TestMarketplaceProductsAPI:
    def test_get_products_empty(self, client, auth_headers):
        """Test getting products when none exist"""
        response = client.get("/api/v1/marketplace/product", headers=auth_headers)

        assert response.status_code == 200
        data = response.json()
        assert data["products"] == []
        assert data["total"] == 0

    def test_get_products_with_data(
        self, client, auth_headers, test_marketplace_product
    ):
        """Test getting products with data"""
        response = client.get("/api/v1/marketplace/product", headers=auth_headers)

        assert response.status_code == 200
        data = response.json()
        assert len(data["products"]) >= 1
        assert data["total"] >= 1
        # Find our test product
        test_product_found = any(
            p["marketplace_product_id"]
            == test_marketplace_product.marketplace_product_id
            for p in data["products"]
        )
        assert test_product_found

    def test_get_products_with_filters(
        self, client, auth_headers, test_marketplace_product
    ):
        """Test filtering products"""
        # Test brand filter
        response = client.get(
            f"/api/v1/marketplace/product?brand={test_marketplace_product.brand}",
            headers=auth_headers,
        )
        assert response.status_code == 200
        data = response.json()
        assert data["total"] >= 1

        # Test marketplace filter
        response = client.get(
            f"/api/v1/marketplace/product?marketplace={test_marketplace_product.marketplace}",
            headers=auth_headers,
        )
        assert response.status_code == 200
        data = response.json()
        assert data["total"] >= 1

        # Test search
        response = client.get(
            "/api/v1/marketplace/product?search=Test", headers=auth_headers
        )
        assert response.status_code == 200
        data = response.json()
        assert data["total"] >= 1

    def test_create_product_success(self, client, auth_headers):
        """Test creating a new product successfully"""
        product_data = {
            "marketplace_product_id": "NEW001",
            "title": "New MarketplaceProduct",
            "description": "A new product",
            "price": "15.99",
            "brand": "NewBrand",
            "gtin": "9876543210987",
            "availability": "in inventory",
            "marketplace": "Amazon",
        }

        response = client.post(
            "/api/v1/marketplace/product", headers=auth_headers, json=product_data
        )

        assert response.status_code == 200
        data = response.json()
        assert data["marketplace_product_id"] == "NEW001"
        assert data["title"] == "New MarketplaceProduct"
        assert data["marketplace"] == "Amazon"

    def test_create_product_duplicate_id_returns_conflict(
        self, client, auth_headers, test_marketplace_product
    ):
        """Test creating product with duplicate ID returns MarketplaceProductAlreadyExistsException"""
        product_data = {
            "marketplace_product_id": test_marketplace_product.marketplace_product_id,
            "title": "Different Title",
            "description": "A new product",
            "price": "15.99",
            "brand": "NewBrand",
            "gtin": "9876543210987",
            "availability": "in inventory",
            "marketplace": "Amazon",
        }

        response = client.post(
            "/api/v1/marketplace/product", headers=auth_headers, json=product_data
        )

        assert response.status_code == 409
        data = response.json()
        assert data["error_code"] == "PRODUCT_ALREADY_EXISTS"
        assert data["status_code"] == 409
        assert test_marketplace_product.marketplace_product_id in data["message"]
        assert (
            data["details"]["marketplace_product_id"]
            == test_marketplace_product.marketplace_product_id
        )

    def test_create_product_missing_title_validation_error(self, client, auth_headers):
        """Test creating product without title returns ValidationException"""
        product_data = {
            "marketplace_product_id": "VALID001",
            "title": "",  # Empty title
            "price": "15.99",
        }

        response = client.post(
            "/api/v1/marketplace/product", headers=auth_headers, json=product_data
        )

        assert response.status_code == 422  # Pydantic validation error
        data = response.json()
        assert data["error_code"] == "PRODUCT_VALIDATION_FAILED"
        assert data["status_code"] == 422
        assert "MarketplaceProduct title is required" in data["message"]
        assert data["details"]["field"] == "title"

    def test_create_product_missing_product_id_validation_error(
        self, client, auth_headers
    ):
        """Test creating product without marketplace_product_id returns ValidationException"""
        product_data = {
            "marketplace_product_id": "",  # Empty product ID
            "title": "Valid Title",
            "price": "15.99",
        }

        response = client.post(
            "/api/v1/marketplace/product", headers=auth_headers, json=product_data
        )

        assert response.status_code == 422
        data = response.json()
        assert data["error_code"] == "PRODUCT_VALIDATION_FAILED"
        assert data["status_code"] == 422
        assert "MarketplaceProduct ID is required" in data["message"]
        assert data["details"]["field"] == "marketplace_product_id"

    def test_create_product_invalid_gtin_data_error(self, client, auth_headers):
        """Test creating product with invalid GTIN returns InvalidMarketplaceProductDataException"""
        product_data = {
            "marketplace_product_id": "GTIN001",
            "title": "GTIN Test MarketplaceProduct",
            "price": "15.99",
            "gtin": "invalid_gtin",
        }

        response = client.post(
            "/api/v1/marketplace/product", headers=auth_headers, json=product_data
        )

        assert response.status_code == 422
        data = response.json()
        assert data["error_code"] == "INVALID_PRODUCT_DATA"
        assert data["status_code"] == 422
        assert "Invalid GTIN format" in data["message"]
        assert data["details"]["field"] == "gtin"

    def test_create_product_invalid_price_data_error(self, client, auth_headers):
        """Test creating product with invalid price returns InvalidMarketplaceProductDataException"""
        product_data = {
            "marketplace_product_id": "PRICE001",
            "title": "Price Test MarketplaceProduct",
            "price": "invalid_price",
        }

        response = client.post(
            "/api/v1/marketplace/product", headers=auth_headers, json=product_data
        )

        assert response.status_code == 422
        data = response.json()
        assert data["error_code"] == "INVALID_PRODUCT_DATA"
        assert data["status_code"] == 422
        assert "Invalid price format" in data["message"]
        assert data["details"]["field"] == "price"

    def test_create_product_request_validation_error(self, client, auth_headers):
        """Test creating product with malformed request returns ValidationException"""
        # Send invalid JSON structure
        product_data = {
            "invalid_field": "value",
            # Missing required fields
        }

        response = client.post(
            "/api/v1/marketplace/product", headers=auth_headers, json=product_data
        )

        assert response.status_code == 422
        data = response.json()
        assert data["error_code"] == "VALIDATION_ERROR"
        assert data["status_code"] == 422
        assert "Request validation failed" in data["message"]
        assert "validation_errors" in data["details"]

    def test_get_product_by_id_success(
        self, client, auth_headers, test_marketplace_product
    ):
        """Test getting specific product successfully"""
        response = client.get(
            f"/api/v1/marketplace/product/{test_marketplace_product.marketplace_product_id}",
            headers=auth_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert (
            data["product"]["marketplace_product_id"]
            == test_marketplace_product.marketplace_product_id
        )
        assert data["product"]["title"] == test_marketplace_product.title

    def test_get_nonexistent_product_returns_not_found(self, client, auth_headers):
        """Test getting nonexistent product returns MarketplaceProductNotFoundException"""
        response = client.get(
            "/api/v1/marketplace/product/NONEXISTENT", headers=auth_headers
        )

        assert response.status_code == 404
        data = response.json()
        assert data["error_code"] == "PRODUCT_NOT_FOUND"
        assert data["status_code"] == 404
        assert "NONEXISTENT" in data["message"]
        assert data["details"]["resource_type"] == "MarketplaceProduct"
        assert data["details"]["identifier"] == "NONEXISTENT"

    def test_update_product_success(
        self, client, auth_headers, test_marketplace_product
    ):
        """Test updating product successfully"""
        update_data = {"title": "Updated MarketplaceProduct Title", "price": "25.99"}

        response = client.put(
            f"/api/v1/marketplace/product/{test_marketplace_product.marketplace_product_id}",
            headers=auth_headers,
            json=update_data,
        )

        assert response.status_code == 200
        data = response.json()
        assert data["title"] == "Updated MarketplaceProduct Title"
        assert data["price"] == "25.99"

    def test_update_nonexistent_product_returns_not_found(self, client, auth_headers):
        """Test updating nonexistent product returns MarketplaceProductNotFoundException"""
        update_data = {"title": "Updated MarketplaceProduct Title"}

        response = client.put(
            "/api/v1/marketplace/product/NONEXISTENT",
            headers=auth_headers,
            json=update_data,
        )

        assert response.status_code == 404
        data = response.json()
        assert data["error_code"] == "PRODUCT_NOT_FOUND"
        assert data["status_code"] == 404
        assert "NONEXISTENT" in data["message"]
        assert data["details"]["resource_type"] == "MarketplaceProduct"
        assert data["details"]["identifier"] == "NONEXISTENT"

    def test_update_product_empty_title_validation_error(
        self, client, auth_headers, test_marketplace_product
    ):
        """Test updating product with empty title returns MarketplaceProductValidationException"""
        update_data = {"title": ""}

        response = client.put(
            f"/api/v1/marketplace/product/{test_marketplace_product.marketplace_product_id}",
            headers=auth_headers,
            json=update_data,
        )

        assert response.status_code == 422
        data = response.json()
        assert data["error_code"] == "PRODUCT_VALIDATION_FAILED"
        assert data["status_code"] == 422
        assert "MarketplaceProduct title cannot be empty" in data["message"]
        assert data["details"]["field"] == "title"

    def test_update_product_invalid_gtin_data_error(
        self, client, auth_headers, test_marketplace_product
    ):
        """Test updating product with invalid GTIN returns InvalidMarketplaceProductDataException"""
        update_data = {"gtin": "invalid_gtin"}

        response = client.put(
            f"/api/v1/marketplace/product/{test_marketplace_product.marketplace_product_id}",
            headers=auth_headers,
            json=update_data,
        )

        assert response.status_code == 422
        data = response.json()
        assert data["error_code"] == "INVALID_PRODUCT_DATA"
        assert data["status_code"] == 422
        assert "Invalid GTIN format" in data["message"]
        assert data["details"]["field"] == "gtin"

    def test_update_product_invalid_price_data_error(
        self, client, auth_headers, test_marketplace_product
    ):
        """Test updating product with invalid price returns InvalidMarketplaceProductDataException"""
        update_data = {"price": "invalid_price"}

        response = client.put(
            f"/api/v1/marketplace/product/{test_marketplace_product.marketplace_product_id}",
            headers=auth_headers,
            json=update_data,
        )

        assert response.status_code == 422
        data = response.json()
        assert data["error_code"] == "INVALID_PRODUCT_DATA"
        assert data["status_code"] == 422
        assert "Invalid price format" in data["message"]
        assert data["details"]["field"] == "price"

    def test_delete_product_success(
        self, client, auth_headers, test_marketplace_product
    ):
        """Test deleting product successfully"""
        response = client.delete(
            f"/api/v1/marketplace/product/{test_marketplace_product.marketplace_product_id}",
            headers=auth_headers,
        )

        assert response.status_code == 200
        assert "deleted successfully" in response.json()["message"]

    def test_delete_nonexistent_product_returns_not_found(self, client, auth_headers):
        """Test deleting nonexistent product returns MarketplaceProductNotFoundException"""
        response = client.delete(
            "/api/v1/marketplace/product/NONEXISTENT", headers=auth_headers
        )

        assert response.status_code == 404
        data = response.json()
        assert data["error_code"] == "PRODUCT_NOT_FOUND"
        assert data["status_code"] == 404
        assert "NONEXISTENT" in data["message"]
        assert data["details"]["resource_type"] == "MarketplaceProduct"
        assert data["details"]["identifier"] == "NONEXISTENT"

    def test_get_product_without_auth_returns_invalid_token(self, client):
        """Test that product endpoints require authentication returns InvalidTokenException"""
        response = client.get("/api/v1/marketplace/product")

        assert response.status_code == 401
        data = response.json()
        assert data["error_code"] == "INVALID_TOKEN"
        assert data["status_code"] == 401

    def test_exception_structure_consistency(self, client, auth_headers):
        """Test that all exceptions follow the consistent WizamartException structure"""
        # Test with a known error case
        response = client.get(
            "/api/v1/marketplace/product/NONEXISTENT", headers=auth_headers
        )

        assert response.status_code == 404
        data = response.json()

        # Verify exception structure matches WizamartException.to_dict()
        required_fields = ["error_code", "message", "status_code"]
        for field in required_fields:
            assert field in data, f"Missing required field: {field}"

        assert isinstance(data["error_code"], str)
        assert isinstance(data["message"], str)
        assert isinstance(data["status_code"], int)

        # Details field should be present for domain-specific exceptions
        if "details" in data:
            assert isinstance(data["details"], dict)
