"""
Service layer for the shared unit-of-measure catalog.
"""

from uuid import UUID

from sqlalchemy.ext.asyncio import AsyncSession

from app.core.exceptions import AlreadyExistsException, ConflictException, NotFoundException
from app.repositories.unit_repository import UnitRepository
from app.schemas.unit import UnitCreate, UnitResponse, UnitUpdate


class UnitService:
    """Business logic for measurement unit administration."""

    def __init__(self, repo: UnitRepository | None = None) -> None:
        self.repo = repo or UnitRepository()

    async def list_units(self, db: AsyncSession, active_only: bool = True) -> list[UnitResponse]:
        units = await self.repo.list_units(db, active_only=active_only)
        return [UnitResponse.model_validate(u) for u in units]

    async def create_unit(self, db: AsyncSession, data: UnitCreate) -> UnitResponse:
        name = data.name.strip()
        if not name:
            raise AlreadyExistsException(message="Unit name must not be blank.")
        existing = await self.repo.get_by_name(db, name)
        if existing:
            raise AlreadyExistsException(message=f"Unit '{existing.name}' already exists.")
        data.name = name
        unit = await self.repo.create_unit(db, data)
        return UnitResponse.model_validate(unit)

    async def update_unit(self, db: AsyncSession, unit_id: UUID, data: UnitUpdate) -> UnitResponse:
        unit = await self.repo.get_by_id(db, unit_id)
        if not unit:
            raise NotFoundException(message=f"Unit with id '{unit_id}' was not found.")
        if data.name is not None:
            name = data.name.strip()
            if not name:
                raise AlreadyExistsException(message="Unit name must not be blank.")
            existing = await self.repo.get_by_name(db, name)
            if existing and existing.id != unit.id:
                raise AlreadyExistsException(message=f"Unit '{existing.name}' already exists.")
            data.name = name
        updated = await self.repo.update_unit(db, unit, data)
        return UnitResponse.model_validate(updated)

    async def delete_unit(self, db: AsyncSession, unit_id: UUID) -> None:
        unit = await self.repo.get_by_id(db, unit_id)
        if not unit:
            raise NotFoundException(message=f"Unit with id '{unit_id}' was not found.")
        if unit.is_system:
            raise ConflictException(
                message=f"System unit '{unit.name}' cannot be deleted. Deactivate it instead."
            )
        await self.repo.delete_unit(db, unit)
