# tests/unit/services/test_admin_customer_service.py
"""
Unit tests for AdminCustomerService.
"""

import pytest

from app.modules.customers.exceptions import CustomerNotFoundException
from app.modules.customers.models.customer import Customer
from app.modules.customers.services.admin_customer_service import AdminCustomerService


@pytest.fixture
def admin_customer_service():
    """Create AdminCustomerService instance."""
    return AdminCustomerService()


@pytest.fixture
def multiple_customers(db, test_store):
    """Create multiple customers for testing."""
    customers = []
    for i in range(5):
        customer = Customer(
            store_id=test_store.id,
            email=f"customer{i}@example.com",
            hashed_password="hashed_password_placeholder",  # noqa: SEC001
            first_name=f"First{i}",
            last_name=f"Last{i}",
            customer_number=f"CUST-00{i}",
            is_active=(i % 2 == 0),  # Alternate active/inactive
        )
        db.add(customer)  # noqa: PERF006
        customers.append(customer)

    db.commit()
    for c in customers:
        db.refresh(c)

    return customers


@pytest.mark.unit
class TestAdminCustomerServiceList:
    """Tests for list_customers method."""

    def test_list_customers_empty(self, db, admin_customer_service, test_store):
        """Test listing customers when none exist."""
        customers, total = admin_customer_service.list_customers(db)

        assert customers == []
        assert total == 0

    def test_list_customers_basic(self, db, admin_customer_service, test_customer):
        """Test basic customer listing."""
        customers, total = admin_customer_service.list_customers(db)

        assert total == 1
        assert len(customers) == 1
        assert customers[0]["id"] == test_customer.id
        assert customers[0]["email"] == test_customer.email

    def test_list_customers_with_store_info(
        self, db, admin_customer_service, test_customer, test_store
    ):
        """Test that store info is included."""
        customers, total = admin_customer_service.list_customers(db)

        assert customers[0]["store_name"] == test_store.name
        assert customers[0]["store_code"] == test_store.store_code

    def test_list_customers_filter_by_store(
        self, db, admin_customer_service, multiple_customers, test_store
    ):
        """Test filtering by store ID."""
        customers, total = admin_customer_service.list_customers(
            db, store_id=test_store.id
        )

        assert total == 5
        for customer in customers:
            assert customer["store_id"] == test_store.id

    def test_list_customers_filter_by_active_status(
        self, db, admin_customer_service, multiple_customers
    ):
        """Test filtering by active status."""
        # Get active customers (0, 2, 4 = 3 customers)
        customers, total = admin_customer_service.list_customers(db, is_active=True)
        assert total == 3

        # Get inactive customers (1, 3 = 2 customers)
        customers, total = admin_customer_service.list_customers(db, is_active=False)
        assert total == 2

    def test_list_customers_search_by_email(
        self, db, admin_customer_service, multiple_customers
    ):
        """Test searching by email."""
        customers, total = admin_customer_service.list_customers(
            db, search="customer2@"
        )

        assert total == 1
        assert customers[0]["email"] == "customer2@example.com"

    def test_list_customers_search_by_name(
        self, db, admin_customer_service, multiple_customers
    ):
        """Test searching by name."""
        customers, total = admin_customer_service.list_customers(db, search="First3")

        assert total == 1
        assert customers[0]["first_name"] == "First3"

    def test_list_customers_search_by_customer_number(
        self, db, admin_customer_service, multiple_customers
    ):
        """Test searching by customer number."""
        customers, total = admin_customer_service.list_customers(db, search="CUST-001")

        assert total == 1
        assert customers[0]["customer_number"] == "CUST-001"

    def test_list_customers_pagination(
        self, db, admin_customer_service, multiple_customers
    ):
        """Test pagination."""
        # Get first page
        customers, total = admin_customer_service.list_customers(db, skip=0, limit=2)
        assert len(customers) == 2
        assert total == 5

        # Get second page
        customers, total = admin_customer_service.list_customers(db, skip=2, limit=2)
        assert len(customers) == 2

        # Get last page
        customers, total = admin_customer_service.list_customers(db, skip=4, limit=2)
        assert len(customers) == 1


@pytest.mark.unit
class TestAdminCustomerServiceStats:
    """Tests for get_customer_stats method."""

    def test_get_customer_stats_empty(self, db, admin_customer_service, test_store):
        """Test stats when no customers exist."""
        stats = admin_customer_service.get_customer_stats(db)

        assert stats["total"] == 0
        assert stats["active"] == 0
        assert stats["inactive"] == 0

    def test_get_customer_stats_with_data(
        self, db, admin_customer_service, multiple_customers
    ):
        """Test stats with customer data."""
        stats = admin_customer_service.get_customer_stats(db)

        assert stats["total"] == 5
        assert stats["active"] == 3  # 0, 2, 4
        assert stats["inactive"] == 2  # 1, 3

    def test_get_customer_stats_by_store(
        self, db, admin_customer_service, test_customer, test_store
    ):
        """Test stats filtered by store."""
        stats = admin_customer_service.get_customer_stats(db, store_id=test_store.id)

        assert stats["total"] == 1


@pytest.mark.unit
class TestAdminCustomerServiceGetCustomer:
    """Tests for get_customer method."""

    def test_get_customer_success(self, db, admin_customer_service, test_customer):
        """Test getting customer by ID."""
        customer = admin_customer_service.get_customer(db, test_customer.id)

        assert customer["id"] == test_customer.id
        assert customer["email"] == test_customer.email
        assert customer["first_name"] == test_customer.first_name
        assert customer["last_name"] == test_customer.last_name

    def test_get_customer_with_store_info(
        self, db, admin_customer_service, test_customer, test_store
    ):
        """Test store info in customer detail."""
        customer = admin_customer_service.get_customer(db, test_customer.id)

        assert customer["store_name"] == test_store.name
        assert customer["store_code"] == test_store.store_code

    def test_get_customer_not_found(self, db, admin_customer_service):
        """Test error when customer not found."""
        with pytest.raises(CustomerNotFoundException):
            admin_customer_service.get_customer(db, 99999)


@pytest.mark.unit
class TestAdminCustomerServiceToggleStatus:
    """Tests for toggle_customer_status method."""

    def test_toggle_status_activate(
        self, db, admin_customer_service, test_customer, test_admin
    ):
        """Test activating an inactive customer."""
        # Make customer inactive first
        test_customer.is_active = False
        db.commit()

        result = admin_customer_service.toggle_customer_status(
            db, test_customer.id, test_admin.email
        )
        db.commit()

        assert result["id"] == test_customer.id
        assert result["is_active"] is True
        assert "activated" in result["message"]

    def test_toggle_status_deactivate(
        self, db, admin_customer_service, test_customer, test_admin
    ):
        """Test deactivating an active customer."""
        test_customer.is_active = True
        db.commit()

        result = admin_customer_service.toggle_customer_status(
            db, test_customer.id, test_admin.email
        )
        db.commit()

        assert result["id"] == test_customer.id
        assert result["is_active"] is False
        assert "deactivated" in result["message"]

    def test_toggle_status_not_found(
        self, db, admin_customer_service, test_admin
    ):
        """Test error when customer not found."""
        with pytest.raises(CustomerNotFoundException):
            admin_customer_service.toggle_customer_status(
                db, 99999, test_admin.email
            )
