package com.betriebsratkanzlei.legalconsenthub.application_form

import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormInvalidStateException
import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormNotCreatedException
import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormNotDeletedException
import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormNotFoundException
import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormNotUpdatedException
import com.betriebsratkanzlei.legalconsenthub.notification.NotificationService
import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormDto
import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormStatus
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateApplicationFormDto
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 java.util.UUID

@Service
class ApplicationFormService(
    private val applicationFormRepository: ApplicationFormRepository,
    private val applicationFormMapper: ApplicationFormMapper,
    private val notificationService: NotificationService
) {

    fun createApplicationForm(createApplicationFormDto: CreateApplicationFormDto): ApplicationForm {
        val applicationForm = applicationFormMapper.toApplicationForm(createApplicationFormDto)
        val savedApplicationForm: ApplicationForm
        try {
            savedApplicationForm = applicationFormRepository.save(applicationForm)
        } catch (e: Exception) {
            throw ApplicationFormNotCreatedException(e)
        }

        return savedApplicationForm
    }

    fun getApplicationFormById(id: UUID): ApplicationForm {
        return applicationFormRepository.findById(id).orElseThrow { ApplicationFormNotFoundException(id) }
    }

    fun getApplicationForms(organizationId: String?): Page<ApplicationForm> {
        val pageable = PageRequest.of(0, 10)
        return applicationFormRepository.findAllByIsTemplateFalseAndOrganizationId(organizationId, pageable)
    }

    fun updateApplicationForm(applicationFormDto: ApplicationFormDto): ApplicationForm {
        // TODO find statt mappen?
        val applicationForm = applicationFormMapper.toApplicationForm(applicationFormDto)
        val updatedApplicationForm: ApplicationForm

        try {
            updatedApplicationForm = applicationFormRepository.save(applicationForm)
        } catch (e: Exception) {
            throw ApplicationFormNotUpdatedException(e, applicationFormDto.id)
        }

        return updatedApplicationForm
    }

    fun deleteApplicationFormByID(id: UUID) {
        try {
            applicationFormRepository.deleteById(id)
        } catch (e: Exception) {
            throw ApplicationFormNotDeletedException(e)
        }
    }

    fun submitApplicationForm(id: UUID): ApplicationForm {
        val applicationForm = getApplicationFormById(id)

        if (applicationForm.status != ApplicationFormStatus.DRAFT) {
            throw ApplicationFormInvalidStateException(
                applicationFormId = id,
                currentState = applicationForm.status,
                expectedState = ApplicationFormStatus.DRAFT,
                operation = "submit"
            )
        }

        applicationForm.status = ApplicationFormStatus.SUBMITTED

        val savedApplicationForm = try {
            applicationFormRepository.save(applicationForm)
        } catch (e: Exception) {
            throw ApplicationFormNotUpdatedException(e, id)
        }

        // Create notifications for relevant users
        createSubmissionNotifications(savedApplicationForm)

        return savedApplicationForm
    }

    private fun createSubmissionNotifications(applicationForm: ApplicationForm) {
        val title = "Neuer Mitbestimmungsantrag eingereicht"
        val message = "Ein neuer Mitbestimmungsantrag '${applicationForm.name}' wurde von ${applicationForm.createdBy.name} eingereicht und wartet auf Ihre Bearbeitung."
        val clickTarget = "/application-forms/${applicationForm.id}/0"

        // Create separate notification for each role that should be notified
        val rolesToNotify = listOf("admin", "works_council_member", "employer", "employee")

        rolesToNotify.forEach { role ->
            notificationService.createNotification(
                title = title,
                message = message,
                clickTarget = clickTarget,
                recipient = null,
                role = role,
                organizationId = applicationForm.organizationId,
                type = NotificationType.INFO
            )
        }
    }
}
