# tests/integration/api/v1/admin/test_order_item_exceptions.py
"""
Integration tests for admin order item exception endpoints.

Tests the /api/v1/admin/order-exceptions/* endpoints.
All endpoints require admin JWT authentication.
"""

import pytest
from datetime import datetime, timezone

from models.database.order import OrderItem
from models.database.order_item_exception import OrderItemException


@pytest.fixture
def test_exception(db, test_order, test_product, test_vendor):
    """Create a test order item exception."""
    # Create an order item
    order_item = OrderItem(
        order_id=test_order.id,
        product_id=test_product.id,
        product_name="Unmatched Product",
        product_sku="UNMATCHED-001",
        quantity=1,
        unit_price=25.00,
        total_price=25.00,
        needs_product_match=True,
    )
    db.add(order_item)
    db.commit()
    db.refresh(order_item)

    # Create exception
    exception = OrderItemException(
        order_item_id=order_item.id,
        vendor_id=test_vendor.id,
        original_gtin="4006381333931",
        original_product_name="Test Missing Product",
        original_sku="MISSING-SKU-001",
        exception_type="product_not_found",
        status="pending",
    )
    db.add(exception)
    db.commit()
    db.refresh(exception)

    return exception


@pytest.mark.integration
@pytest.mark.api
@pytest.mark.admin
class TestAdminOrderItemExceptionAPI:
    """Tests for admin order item exception endpoints."""

    # ========================================================================
    # List & Statistics Tests
    # ========================================================================

    def test_list_exceptions(self, client, admin_headers, test_exception):
        """Test listing order item exceptions."""
        response = client.get(
            "/api/v1/admin/order-exceptions",
            headers=admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert "exceptions" in data
        assert "total" in data
        assert data["total"] >= 1

    def test_list_exceptions_non_admin(self, client, auth_headers):
        """Test non-admin cannot access exceptions endpoint."""
        response = client.get(
            "/api/v1/admin/order-exceptions",
            headers=auth_headers,
        )

        assert response.status_code == 403

    def test_list_exceptions_with_status_filter(
        self, client, admin_headers, test_exception
    ):
        """Test filtering exceptions by status."""
        response = client.get(
            "/api/v1/admin/order-exceptions",
            params={"status": "pending"},
            headers=admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        for exc in data["exceptions"]:
            assert exc["status"] == "pending"

    def test_get_exception_stats(self, client, admin_headers, test_exception):
        """Test getting exception statistics."""
        response = client.get(
            "/api/v1/admin/order-exceptions/stats",
            headers=admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert "pending" in data
        assert "resolved" in data
        assert "ignored" in data
        assert "total" in data
        assert data["pending"] >= 1

    # ========================================================================
    # Get Single Exception
    # ========================================================================

    def test_get_exception_by_id(self, client, admin_headers, test_exception):
        """Test getting a single exception by ID."""
        response = client.get(
            f"/api/v1/admin/order-exceptions/{test_exception.id}",
            headers=admin_headers,
        )

        assert response.status_code == 200
        data = response.json()
        assert data["id"] == test_exception.id
        assert data["original_gtin"] == test_exception.original_gtin
        assert data["status"] == "pending"

    def test_get_exception_not_found(self, client, admin_headers):
        """Test getting non-existent exception."""
        response = client.get(
            "/api/v1/admin/order-exceptions/99999",
            headers=admin_headers,
        )

        assert response.status_code == 404

    # ========================================================================
    # Resolution Tests
    # ========================================================================

    def test_resolve_exception(
        self, client, admin_headers, test_exception, test_product
    ):
        """Test resolving an exception by assigning a product."""
        response = client.post(
            f"/api/v1/admin/order-exceptions/{test_exception.id}/resolve",
            headers=admin_headers,
            json={
                "product_id": test_product.id,
                "notes": "Matched to existing product",
            },
        )

        assert response.status_code == 200
        data = response.json()
        assert data["status"] == "resolved"
        assert data["resolved_product_id"] == test_product.id
        assert data["resolution_notes"] == "Matched to existing product"

    def test_ignore_exception(self, client, admin_headers, test_exception):
        """Test ignoring an exception."""
        response = client.post(
            f"/api/v1/admin/order-exceptions/{test_exception.id}/ignore",
            headers=admin_headers,
            json={
                "notes": "Product discontinued, will never be matched",
            },
        )

        assert response.status_code == 200
        data = response.json()
        assert data["status"] == "ignored"
        assert "discontinued" in data["resolution_notes"]

    def test_resolve_already_resolved(
        self, client, admin_headers, db, test_exception, test_product
    ):
        """Test that resolving an already resolved exception fails."""
        # First resolve it
        test_exception.status = "resolved"
        test_exception.resolved_product_id = test_product.id
        test_exception.resolved_at = datetime.now(timezone.utc)
        db.commit()

        # Try to resolve again
        response = client.post(
            f"/api/v1/admin/order-exceptions/{test_exception.id}/resolve",
            headers=admin_headers,
            json={
                "product_id": test_product.id,
            },
        )

        assert response.status_code == 400

    # ========================================================================
    # Bulk Resolution Tests
    # ========================================================================

    def test_bulk_resolve_by_gtin(
        self, client, admin_headers, db, test_order, test_product, test_vendor
    ):
        """Test bulk resolving exceptions by GTIN."""
        gtin = "9876543210123"

        # Create multiple exceptions for the same GTIN
        for i in range(3):
            order_item = OrderItem(
                order_id=test_order.id,
                product_id=test_product.id,
                product_name=f"Product {i}",
                product_sku=f"SKU-{i}",
                quantity=1,
                unit_price=10.00,
                total_price=10.00,
                needs_product_match=True,
            )
            db.add(order_item)
            db.commit()

            exception = OrderItemException(
                order_item_id=order_item.id,
                vendor_id=test_vendor.id,
                original_gtin=gtin,
                original_product_name=f"Product {i}",
                exception_type="product_not_found",
            )
            db.add(exception)
        db.commit()

        # Bulk resolve
        response = client.post(
            "/api/v1/admin/order-exceptions/bulk-resolve",
            params={"vendor_id": test_vendor.id},
            headers=admin_headers,
            json={
                "gtin": gtin,
                "product_id": test_product.id,
                "notes": "Bulk resolved during import",
            },
        )

        assert response.status_code == 200
        data = response.json()
        assert data["resolved_count"] == 3
        assert data["gtin"] == gtin
        assert data["product_id"] == test_product.id
