from __future__ import annotations

from typing import TypeVar
from uuid import UUID

from sqlalchemy.orm import Session

from fastapi import HTTPException, status

from app.models.contact import Contact
from app.models.customer import Customer
from app.models.device import Device
from app.models.equipment import Equipment
from app.models.location import Location
from app.models.user import User, UserRole
from app.models.validation import Validation
from app.repositories.base import Repository
from app.repositories.domain import (
    ContactRepository,
    CustomerRepository,
    DeviceRepository,
    EquipmentRepository,
    LocationRepository,
    UserRepository,
    ValidationRepository,
)

ModelT = TypeVar("ModelT")


class CrudService:
    def __init__(self, repository: Repository[ModelT]) -> None:
        self.repository = repository

    def list(self, page: int = 1, page_size: int = 20, search: str | None = None) -> dict:
        safe_page = max(page, 1)
        safe_page_size = min(max(page_size, 1), 100)
        offset = (safe_page - 1) * safe_page_size
        return {
            "items": self.repository.list(safe_page_size, offset, search),
            "total": self.repository.count(search),
            "page": safe_page,
            "page_size": safe_page_size,
        }

    def create(self, data: dict) -> ModelT:
        data = self._normalize(data)
        return self.repository.add(self.repository.model(**data))

    def update(self, item_id: str, data: dict) -> ModelT:
        data = self._normalize(data)
        item = self.repository.get(item_id)
        if item is None:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Resource not found")
        if isinstance(item, Validation) and item.status in {"FREIGEGEBEN", "ABGESCHLOSSEN"}:
            raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Freigegebene oder abgeschlossene Validierungen sind schreibgeschuetzt")
        for key, value in data.items():
            setattr(item, key, value)
        return item

    def _normalize(self, data: dict) -> dict:
        normalized = {}
        for key, value in data.items():
            if key.endswith("_id") and value == "":
                normalized[key] = None
            elif isinstance(value, UUID):
                normalized[key] = str(value)
            elif isinstance(value, list):
                normalized[key] = [str(item) if isinstance(item, UUID) else item for item in value]
            else:
                normalized[key] = value
        return normalized

    def delete(self, item_id: str) -> None:
        item = self.repository.get(item_id)
        if item is None:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Resource not found")
        self.repository.delete(item)


class DomainServices:
    def __init__(self, session: Session) -> None:
        self.users: CrudService[User] = CrudService(UserRepository(session))
        self.customers: CrudService[Customer] = CrudService(CustomerRepository(session))
        self.locations: CrudService[Location] = CrudService(LocationRepository(session))
        self.contacts: CrudService[Contact] = CrudService(ContactRepository(session))
        self.devices: CrudService[Device] = CrudService(DeviceRepository(session))
        self.equipment: CrudService[Equipment] = CrudService(EquipmentRepository(session))
        self.validations: CrudService[Validation] = CrudService(ValidationRepository(session))
