import re
from django.db import transaction
from django.db import IntegrityError
from django.utils.timezone import now
from django.utils.text import slugify
from rest_framework.exceptions import ValidationError
from apps.companies.repositories import (
    ServiceRepository, ServicePriceRepository
)


class ServiceDomainService:

    @staticmethod
    def generate_code_from_name(name: str) -> str:
        """
        Convert name to enterprise-safe code:
        "Oil Change Basic" -> "OIL_CHANGE_BASIC"
        """
        code = slugify(name).replace("-", "_").upper()
        return re.sub(r"[^A-Z0-9_]", "", code)

    @classmethod
    def create_service(cls, *, name, description, company):
        code = cls.generate_code_from_name(name)

        if ServiceRepository.service_exists(company, code):
            raise ValidationError(
                {"name": "Service with this name already exists."}
            )

        return ServiceRepository.create_service(
            company=company,
            name=name,
            description=description,
            code=code,
            is_active=True,   # Always backend controlled
        )

    @classmethod
    def update_service(cls, pk, name, description, company, is_active):
        code = cls.generate_code_from_name(name)

        if ServiceRepository.service_exists(company, code, exclude_pk=pk):
            raise ValidationError(
                {"name": "Service with this name already exists."}
            )

        return ServiceRepository.update_service(
            pk=pk,
            company=company,
            name=name,
            description=description,
            code=code,
            is_active=is_active,
        )

    @classmethod
    def create_service_with_price(cls, *, name, description, company, price_data):
        """
        Creates a Service and its initial ServicePrice atomically.
        """
        with transaction.atomic():
            service = cls.create_service(
                name=name,
                description=description,
                company=company
            )

            price_data.setdefault("is_active", True)
            price_data.setdefault("starting_at", False)
            price_data.setdefault("effective_from", now().date())

            price = ServicePriceDomainService.create_price(
                service=service,
                company=company,
                **price_data
            )

        return service, price

class ServicePriceDomainService:

    @staticmethod
    def _normalize_price_data(service, company, data):
        data["service"] = service
        data["company"] = company
        data["is_active"] = data.get("is_active", True)
        data["starting_at"] = data.get("starting_at", False)
        data["effective_from"] = data.get("effective_from") or now().date()
        return data

    @staticmethod
    def create_price(*, service, company, **data):

        if ServicePriceRepository.price_exists(
            service,
            company,
            data.get("effective_from")
        ):
            raise ValidationError(
                {"service": "Price already exists for this service and date."}
            )

        data = ServicePriceDomainService._normalize_price_data(service, company, data)

        try:
            return ServicePriceRepository.create_price(**data)
        except IntegrityError:
            raise ValidationError({
                "service": "A price already exists for this service and date."
            })

    @staticmethod
    def update_price(*, pk, service, company, **data):

        if ServicePriceRepository.price_exists(
            service,
            company,
            data.get("effective_from"),
            exclude_pk=pk,
        ):
            raise ValidationError(
                {"service": "Price already exists for this service and date."}
            )

        data = ServicePriceDomainService._normalize_price_data(service, company, data)
        return ServicePriceRepository.update_price(pk=pk, **data)
