import logging

from django.db.utils import InternalError as DjangoUtilsInternalError

from staff.lib.db import atomic
from staff.map.edit.objects import RoomCtl


logger = logging.getLogger(__name__)


@atomic
def update_room_common(ctl_type, exception_type, room, data, author) -> None:
    def _update_room():
        ctl = ctl_type(room, author)
        ctl.update(data)
        ctl.save()

    _handle_geometry_error(exception_type, _update_room, 'update', room.id)


@atomic
def create_room_common(ctl_type, exception_type, data, author) -> RoomCtl:
    return _handle_geometry_error(exception_type, lambda: ctl_type.create(data, author), 'create', data)


@atomic
def delete_room_common(ctl_type, exception_type, room, author) -> RoomCtl:
    return _handle_geometry_error(exception_type, ctl_type(room, author).disable, 'delete', room.id)


def _handle_geometry_error(exception_type, action, action_type, room_data):
    try:
        return action()
    except DjangoUtilsInternalError as e:
        if e.args[0].startswith('geometry contains non-closed rings'):
            logger.info('DB error: geometry contains non-closed rings for room %s', room_data)
            raise exception_type('geometry-contains-non-closed-rings', 400)
        logger.exception('DB error on %s room %s', action_type, room_data)
        raise exception_type(f'cannot-{action_type}-conferenceroom', 500)
    except Exception:
        logger.exception('Error trying to %s room %s', action_type, room_data)
        raise exception_type(f'cannot-{action_type}-conferenceroom', 500)
