from pathlib import Path
from otree.models_concrete import RoomToSession
from otree.common import add_params_to_url, make_hash, validate_alphanumeric
from django.conf import settings
from django.urls import reverse
from django.db import transaction


class Room:
    def __init__(
        self, name, display_name, use_secure_urls=False, participant_label_file=None
    ):
        self.name = validate_alphanumeric(
            name, identifier_description='settings.ROOMS room name'
        )
        if use_secure_urls and not participant_label_file:
            msg = (
                'Room "{}": you must either set "participant_label_file", '
                'or set "use_secure_urls": False'.format(name)
            )
            raise ValueError(msg)
        self.participant_label_file = participant_label_file
        self.display_name = display_name
        # secure URLs are complicated, don't use them by default
        self.use_secure_urls = use_secure_urls

    def has_session(self):
        return self.get_session() is not None

    def get_session(self):
        try:
            return (
                RoomToSession.objects.select_related('session')
                .get(room_name=self.name)
                .session
            )
        except RoomToSession.DoesNotExist:
            return None

    def set_session(self, session):
        with transaction.atomic():
            RoomToSession.objects.filter(room_name=self.name).delete()
            if session:
                RoomToSession.objects.create(room_name=self.name, session=session)

    def has_participant_labels(self):
        return bool(self.participant_label_file)

    def get_participant_labels(self):
        labels = Path(self.participant_label_file).read_text(encoding='utf8').split()
        for label in labels:
            validate_alphanumeric(label, identifier_description='participant label')
        # eliminate duplicates
        return list(dict.fromkeys(labels))

    def get_room_wide_url(self, request):
        url = reverse('AssignVisitorToRoom', args=(self.name,))
        return request.build_absolute_uri(url)

    def get_participant_urls(self, request):
        participant_urls = []
        room_base_url = reverse('AssignVisitorToRoom', args=(self.name,))
        room_base_url = request.build_absolute_uri(room_base_url)

        if self.has_participant_labels():
            for label in self.get_participant_labels():
                params = {'participant_label': label}
                if self.use_secure_urls:
                    params['hash'] = make_hash(label)
                participant_url = add_params_to_url(room_base_url, params)
                participant_urls.append(participant_url)

        return participant_urls


def get_room_dict():
    ROOM_DEFAULTS = getattr(settings, 'ROOM_DEFAULTS', {})
    ROOMS = getattr(settings, 'ROOMS', [])
    ROOM_DICT = {}
    for room in ROOMS:
        # extra layer in case ROOM_DEFAULTS has the same key
        # as a room
        room_object = Room(**dict(ROOM_DEFAULTS, **room))
        ROOM_DICT[room_object.name] = room_object
    return ROOM_DICT


ROOM_DICT = get_room_dict()
