# This file is part of Indico.
# Copyright (C) 2002 - 2026 CERN
#
# Indico is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see the
# LICENSE file for more details.

from enum import Enum

from flask import request, session
from werkzeug.exceptions import Forbidden, NotFound

from indico.modules.events.management.controllers import RHManageEventBase
from indico.modules.events.timetable import TimetableEntryType


class SessionManagementLevel(Enum):
    none = 0
    manage = 1
    coordinate_with_blocks = 2
    coordinate_with_contribs = 3
    coordinate = 4


class RHManageTimetableBase(RHManageEventBase):
    """Base class for all timetable management RHs."""

    session_management_level = SessionManagementLevel.none

    def _process_args(self):
        RHManageEventBase._process_args(self)
        self.session = None
        if 'session_id' in request.view_args:
            self.session = self.event.get_session(request.view_args['session_id'])
            if self.session is None:
                raise NotFound

    def _check_access(self):
        if not self.session or self.session_management_level == SessionManagementLevel.none:
            RHManageEventBase._check_access(self)
        else:
            if self.session_management_level == SessionManagementLevel.manage:
                func = lambda u: self.session.can_manage(u)
            elif self.session_management_level == SessionManagementLevel.coordinate_with_blocks:
                func = lambda u: self.session.can_manage_blocks(u)
            elif self.session_management_level == SessionManagementLevel.coordinate_with_contribs:
                func = lambda u: self.session.can_manage_contributions(u)
            elif self.session_management_level == SessionManagementLevel.coordinate:
                func = lambda u: self.session.can_manage(u, permission='coordinate')
            else:
                raise Exception('Invalid session management level')
            if not func(session.user):
                raise Forbidden


class RHManageTimetableEntryBase(RHManageTimetableBase):
    normalize_url_spec = {
        'locators': {
            lambda self: self._get_locator()
        }
    }

    def _get_locator(self):
        if not self.entry:
            return self.event
        locator = self.entry.locator
        if 'session_id' in request.view_args:
            locator['session_id'] = self.session.id
        return locator

    def _process_args(self):
        RHManageTimetableBase._process_args(self)
        self.entry = None
        if 'entry_id' in request.view_args:
            self.entry = self.event.timetable_entries.filter_by(id=request.view_args['entry_id']).first_or_404()

    def _check_access(self):
        if self.session and self.entry:
            entry_session = None
            if self.entry.parent and self.entry.parent.type == TimetableEntryType.SESSION_BLOCK:
                entry_session = self.entry.parent.session_block.session
            elif self.entry.type == TimetableEntryType.SESSION_BLOCK:
                entry_session = self.entry.session_block.session
            if entry_session != self.session:
                raise Forbidden('Timetable entry is not in the specified session')
        RHManageTimetableBase._check_access(self)
