package com.betriebsratkanzlei.legalconsenthub.notification

import com.betriebsratkanzlei.legalconsenthub.security.CustomJwtTokenPrincipal
import com.betriebsratkanzlei.legalconsenthub_api.api.NotificationApi
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateNotificationDto
import com.betriebsratkanzlei.legalconsenthub_api.model.NotificationDto
import com.betriebsratkanzlei.legalconsenthub_api.model.PagedNotificationDto
import org.springframework.http.ResponseEntity
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.web.bind.annotation.RestController
import java.util.UUID

@RestController
class NotificationController(
    private val notificationService: NotificationService,
    private val notificationMapper: NotificationMapper,
    private val pagedNotificationMapper: PagedNotificationMapper,
) : NotificationApi {
    @PreAuthorize(
        "hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')",
    )
    override fun getNotifications(
        organizationId: String,
        page: Int,
        size: Int,
    ): ResponseEntity<PagedNotificationDto> {
        val principal = SecurityContextHolder.getContext().authentication.principal as CustomJwtTokenPrincipal
        val recipientId = principal.id ?: throw IllegalStateException("User ID not found")
        validateOrganizationAccess(principal, organizationId)
        val userRoles = principal.roles

        val notifications =
            notificationService.getNotifications(
                recipientKeycloakId = recipientId,
                organizationId = organizationId,
                userRoles = userRoles,
                page = page,
                size = size,
            )

        return ResponseEntity.ok(pagedNotificationMapper.toPagedNotificationDto(notifications))
    }

    @PreAuthorize(
        "hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')",
    )
    override fun getUnreadNotifications(organizationId: String): ResponseEntity<List<NotificationDto>> {
        val principal = SecurityContextHolder.getContext().authentication.principal as CustomJwtTokenPrincipal
        val recipientId = principal.id ?: throw IllegalStateException("User ID not found")
        validateOrganizationAccess(principal, organizationId)
        val userRoles = principal.roles

        val notifications =
            notificationService.getUnreadNotifications(
                recipientKeycloakId = recipientId,
                organizationId = organizationId,
                userRoles = userRoles,
            )

        return ResponseEntity.ok(notifications.map { notificationMapper.toNotificationDto(it) })
    }

    override fun getUnreadNotificationCount(
        userId: String,
        organizationId: String,
    ): ResponseEntity<kotlin.Long> {
        val count =
            notificationService.getUnreadNotificationCount(
                recipientKeycloakId = userId,
                organizationId = organizationId,
                userRoles = emptyList(),
            )

        return ResponseEntity.ok(count)
    }

    @PreAuthorize(
        "hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')",
    )
    override fun markAllNotificationsAsRead(organizationId: String): ResponseEntity<Unit> {
        val principal = SecurityContextHolder.getContext().authentication.principal as CustomJwtTokenPrincipal
        val recipientId = principal.id ?: throw IllegalStateException("User ID not found")
        validateOrganizationAccess(principal, organizationId)

        notificationService.markAllAsRead(
            recipientKeycloakId = recipientId,
            organizationId = organizationId,
        )

        return ResponseEntity.noContent().build()
    }

    @PreAuthorize(
        "hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')",
    )
    override fun markNotificationAsRead(
        id: UUID,
        organizationId: String,
    ): ResponseEntity<NotificationDto> {
        val principal = SecurityContextHolder.getContext().authentication.principal as CustomJwtTokenPrincipal
        validateOrganizationAccess(principal, organizationId)

        val notification = notificationService.markNotificationAsRead(id)
        return ResponseEntity.ok(notificationMapper.toNotificationDto(notification))
    }

    @PreAuthorize(
        "hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL')",
    )
    override fun createNotification(createNotificationDto: CreateNotificationDto): ResponseEntity<NotificationDto> {
        val principal = SecurityContextHolder.getContext().authentication.principal as CustomJwtTokenPrincipal
        validateOrganizationAccess(principal, createNotificationDto.organizationId)

        val notification =
            when {
                createNotificationDto.recipientId != null ->
                    notificationService.createNotificationForUser(createNotificationDto)
                !createNotificationDto.targetRoles.isNullOrEmpty() ->
                    notificationService.createNotificationForRoles(createNotificationDto)
                else ->
                    notificationService.createNotificationForOrganization(createNotificationDto)
            }

        return ResponseEntity.ok(notificationMapper.toNotificationDto(notification))
    }

    @PreAuthorize(
        "hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')",
    )
    override fun clearAllNotifications(organizationId: String): ResponseEntity<Unit> {
        val principal = SecurityContextHolder.getContext().authentication.principal as CustomJwtTokenPrincipal
        val recipientId = principal.id ?: throw IllegalStateException("User ID not found")
        validateOrganizationAccess(principal, organizationId)

        notificationService.clearAllNotifications(
            recipientKeycloakId = recipientId,
            organizationId = organizationId,
        )

        return ResponseEntity.noContent().build()
    }

    private fun validateOrganizationAccess(
        principal: CustomJwtTokenPrincipal,
        organizationId: String,
    ) {
        if (organizationId !in principal.organizationIds) {
            throw SecurityException("User is not authorized to access organization: $organizationId")
        }
    }
}
