package com.betriebsratkanzlei.legalconsenthub.notification

import com.betriebsratkanzlei.legalconsenthub.user.User
import com.betriebsratkanzlei.legalconsenthub.user.UserRepository
import com.betriebsratkanzlei.legalconsenthub.user.UserRoleConverter
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateNotificationDto
import com.betriebsratkanzlei.legalconsenthub_api.model.NotificationType
import org.springframework.data.domain.Page
import org.springframework.data.domain.PageRequest
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.util.UUID

@Service
class NotificationService(
    private val notificationRepository: NotificationRepository,
    private val notificationMapper: NotificationMapper,
    private val userRepository: UserRepository,
    private val userRoleConverter: UserRoleConverter
) {

    fun createNotification(createNotificationDto: CreateNotificationDto): Notification {
        val notification = notificationMapper.toNotification(createNotificationDto)
        return notificationRepository.save(notification)
    }

    fun createNotification(
        title: String,
        message: String,
        clickTarget: String,
        recipient: User?,
        role: String,
        organizationId: String,
        type: NotificationType = NotificationType.INFO
    ): Notification {
        val notification = Notification(
            title = title,
            message = message,
            clickTarget = clickTarget,
            recipient = recipient,
            role = role,
            type = type,
            organizationId = organizationId
        )
        return notificationRepository.save(notification)
    }

    fun getNotifications(
        recipientId: String,
        organizationId: String,
        page: Int = 0,
        size: Int = 20
    ): Page<Notification> {
        val user = userRepository.findById(recipientId)
            .orElseThrow { IllegalArgumentException("User not found with id: $recipientId") }

        val userRoles = userRoleConverter.getRolesForOrganization(user.organizationRoles, organizationId)
        val orgRolePairs = userRoles.map { role -> "$organizationId:${role.value}" }

        val pageable = PageRequest.of(page, size)
        return if (userRoles.isNotEmpty()) {
            notificationRepository.findUserNotificationsByOrgRole(recipientId, listOf(organizationId), orgRolePairs, pageable)
        } else {
            notificationRepository.findByRecipientIdOrderByCreatedAtDesc(recipientId, pageable)
        }
    }

    fun getUnreadNotifications(
        recipientId: String,
        organizationId: String
    ): List<Notification> {
        val user = userRepository.findById(recipientId)
            .orElseThrow { IllegalArgumentException("User not found with id: $recipientId") }

        val userRoles = userRoleConverter.getRolesForOrganization(user.organizationRoles, organizationId)
        val orgRolePairs = userRoles.map { role -> "$organizationId:${role.value}" }

        return if (userRoles.isNotEmpty()) {
            notificationRepository.findUnreadUserNotificationsByOrgRole(recipientId, listOf(organizationId), orgRolePairs)
        } else {
            notificationRepository.findByRecipientIdAndIsReadFalseOrderByCreatedAtDesc(recipientId)
        }
    }

    fun getUnreadNotificationCount(
        recipientId: String,
        organizationId: String
    ): Long {
        val user = userRepository.findById(recipientId)
            .orElseThrow { IllegalArgumentException("User not found with id: $recipientId") }

        val userRoles = userRoleConverter.getRolesForOrganization(user.organizationRoles, organizationId)
        val orgRolePairs = userRoles.map { role -> "$organizationId:${role.value}" }

        return if (userRoles.isNotEmpty()) {
            notificationRepository.countUnreadUserNotifications(recipientId, listOf(organizationId), orgRolePairs)
        } else {
            notificationRepository.countByRecipientIdAndIsReadFalse(recipientId)
        }
    }

    @Transactional
    fun markAllAsRead(
        recipientId: String,
        organizationId: String
    ) {
        val user = userRepository.findById(recipientId)
            .orElseThrow { IllegalArgumentException("User not found with id: $recipientId") }

        val userRoles = userRoleConverter.getRolesForOrganization(user.organizationRoles, organizationId)
        val orgRolePairs = userRoles.map { role -> "$organizationId:${role.value}" }

        if (userRoles.isNotEmpty()) {
            notificationRepository.markAllUserNotificationsAsRead(recipientId, listOf(organizationId), orgRolePairs)
        } else {
            notificationRepository.markAllAsReadByRecipientId(recipientId)
        }
    }

    @Transactional
    fun markNotificationAsRead(notificationId: UUID): Notification {
        val notification = notificationRepository.findById(notificationId)
            .orElseThrow { IllegalArgumentException("Notification not found with id: $notificationId") }
        notification.isRead = true
        return notificationRepository.save(notification)
    }
}
