# app/modules/hosting/tests/unit/test_client_service_service.py
"""
Unit tests for ClientServiceService.
"""

from datetime import UTC, datetime, timedelta

import pytest

from app.modules.hosting.exceptions import ClientServiceNotFoundException
from app.modules.hosting.models import ClientServiceStatus, ServiceType
from app.modules.hosting.services.client_service_service import ClientServiceService


@pytest.mark.unit
@pytest.mark.hosting
class TestClientServiceService:
    """Tests for ClientServiceService CRUD operations."""

    def setup_method(self):
        self.service = ClientServiceService()

    def test_create_domain_service(self, db, hosted_site):
        """Test creating a domain service."""
        svc = self.service.create(
            db,
            hosted_site.id,
            {
                "service_type": "domain",
                "name": "example.lu",
                "domain_name": "example.lu",
                "registrar": "Gandi",
                "billing_period": "annual",
                "price_cents": 1500,
            },
        )
        db.commit()

        assert svc.id is not None
        assert svc.service_type == ServiceType.DOMAIN
        assert svc.status == ClientServiceStatus.PENDING
        assert svc.domain_name == "example.lu"
        assert svc.registrar == "Gandi"
        assert svc.price_cents == 1500

    def test_create_email_service(self, db, hosted_site):
        """Test creating an email service."""
        svc = self.service.create(
            db,
            hosted_site.id,
            {
                "service_type": "email",
                "name": "Email Hosting",
                "mailbox_count": 10,
                "billing_period": "monthly",
                "price_cents": 900,
            },
        )
        db.commit()

        assert svc.service_type == ServiceType.EMAIL
        assert svc.mailbox_count == 10

    def test_create_ssl_service(self, db, hosted_site):
        """Test creating an SSL service."""
        svc = self.service.create(
            db,
            hosted_site.id,
            {
                "service_type": "ssl",
                "name": "Let's Encrypt SSL",
                "price_cents": 0,
                "expires_at": datetime.now(UTC) + timedelta(days=90),
            },
        )
        db.commit()

        assert svc.service_type == ServiceType.SSL
        assert svc.expires_at is not None

    def test_create_hosting_service(self, db, hosted_site):
        """Test creating a hosting service."""
        svc = self.service.create(
            db,
            hosted_site.id,
            {
                "service_type": "hosting",
                "name": "Shared Hosting",
                "billing_period": "monthly",
                "price_cents": 2000,
            },
        )
        db.commit()

        assert svc.service_type == ServiceType.HOSTING

    def test_create_maintenance_service(self, db, hosted_site):
        """Test creating a website maintenance service."""
        svc = self.service.create(
            db,
            hosted_site.id,
            {
                "service_type": "website_maintenance",
                "name": "Monthly Maintenance",
                "billing_period": "monthly",
                "price_cents": 5000,
                "notes": "Includes security updates",
            },
        )
        db.commit()

        assert svc.service_type == ServiceType.WEBSITE_MAINTENANCE
        assert svc.notes == "Includes security updates"

    def test_get_by_id(self, db, client_service_domain):
        """Test getting a service by ID."""
        result = self.service.get_by_id(db, client_service_domain.id)
        assert result.id == client_service_domain.id

    def test_get_by_id_not_found(self, db):
        """Test getting non-existent service raises exception."""
        with pytest.raises(ClientServiceNotFoundException):
            self.service.get_by_id(db, 99999)

    def test_get_for_site(self, db, hosted_site, client_service_domain, client_service_email):
        """Test getting all services for a site."""
        services = self.service.get_for_site(db, hosted_site.id)
        assert len(services) >= 2

    def test_update_service(self, db, client_service_domain):
        """Test updating a service."""
        updated = self.service.update(
            db,
            client_service_domain.id,
            {"name": "updated-domain.lu", "price_cents": 3000},
        )
        db.commit()

        assert updated.name == "updated-domain.lu"
        assert updated.price_cents == 3000

    def test_update_service_status(self, db, client_service_domain):
        """Test updating a service status."""
        updated = self.service.update(
            db,
            client_service_domain.id,
            {"status": ClientServiceStatus.SUSPENDED},
        )
        db.commit()

        assert updated.status == ClientServiceStatus.SUSPENDED

    def test_delete_service(self, db, client_service_domain):
        """Test deleting a service."""
        svc_id = client_service_domain.id
        self.service.delete(db, svc_id)
        db.commit()

        with pytest.raises(ClientServiceNotFoundException):
            self.service.get_by_id(db, svc_id)

    def test_get_expiring_soon(self, db, client_service_expiring):
        """Test getting services expiring within 30 days."""
        expiring = self.service.get_expiring_soon(db, days=30)
        assert len(expiring) >= 1
        assert all(s.expires_at is not None for s in expiring)

    def test_get_expiring_soon_excludes_distant(self, db, client_service_domain):
        """Test that services expiring far in the future are excluded."""
        # client_service_domain expires in 365 days
        expiring = self.service.get_expiring_soon(db, days=30)
        ids = [s.id for s in expiring]
        assert client_service_domain.id not in ids

    def test_get_all(self, db, client_service_domain, client_service_email):
        """Test listing all services with pagination."""
        services, total = self.service.get_all(db)
        assert total >= 2
        assert len(services) >= 2

    def test_get_all_filter_type(self, db, client_service_domain, client_service_email):
        """Test filtering services by type."""
        services, total = self.service.get_all(db, service_type="domain")
        assert total >= 1
        assert all(s.service_type == ServiceType.DOMAIN for s in services)

    def test_get_all_filter_status(self, db, client_service_domain):
        """Test filtering services by status."""
        services, total = self.service.get_all(db, status="active")
        assert total >= 1
        assert all(s.status == ClientServiceStatus.ACTIVE for s in services)

    def test_get_all_pagination(self, db, client_service_domain, client_service_email):
        """Test pagination."""
        services, total = self.service.get_all(db, page=1, per_page=1)
        assert len(services) == 1
        assert total >= 2

    def test_default_currency(self, db, hosted_site):
        """Test that default currency is EUR."""
        svc = self.service.create(
            db,
            hosted_site.id,
            {"service_type": "hosting", "name": "Test"},
        )
        db.commit()

        assert svc.currency == "EUR"

    def test_auto_renew_default(self, db, hosted_site):
        """Test that auto_renew defaults to True."""
        svc = self.service.create(
            db,
            hosted_site.id,
            {"service_type": "hosting", "name": "Test"},
        )
        db.commit()

        assert svc.auto_renew is True
