package com.isidroid.c23.domain.use_case

import android.content.Context
import android.graphics.BitmapFactory
import android.net.Uri
import androidx.compose.ui.unit.IntSize
import com.isidroid.c23.R
import com.isidroid.c23.SpotHasNoPrintProfilesException
import com.isidroid.job_sender.SendJobWorker
import com.isidroid.c23.ext.transformToBitmapFiles
import com.isidroid.core.FlowResult
import com.isidroid.job.repository.JobRepository
import com.isidroid.rendering.constant.PrintOrientation
import com.isidroid.rendering.constant.PrintSize
import com.isidroid.rendering.model.RenderResult
import com.isidroid.rendering.model.RenderSettingsV2
import com.isidroid.rendering.repository.RenderRepository
import com.isidroid.spot.model.PrintProfile
import com.isidroid.spot.repository.ActiveSpotRepository
import com.isidroid.utils.saveToFile
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.flow
import java.io.File
import java.util.UUID
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class RenderUseCase @Inject constructor(
    @ApplicationContext private val context: Context,
    private val renderRepository: RenderRepository,
    private val spotRepository: ActiveSpotRepository,
    private val jobRepository: JobRepository
) {

    fun loadSpot() = flow {
        val richSpot = spotRepository.getDefaultSpot()
        if (richSpot?.printProfiles.isNullOrEmpty())
            throw SpotHasNoPrintProfilesException(context.getString(R.string.error_spot_has_no_printing_profiles))

        emit(richSpot!!)
    }

    fun render(
        sourceFile: File?,
        containerSize: IntSize?,
        printProfile: PrintProfile?,
        renderSettings: RenderSettingsV2?
    ) = flow {
        sourceFile ?: throw IllegalStateException("Uri is null")
        containerSize ?: throw IllegalStateException("Container size is null")
        printProfile ?: throw IllegalStateException("Profile is null")
        renderSettings ?: throw IllegalStateException("renderSettings is null")

        emit(FlowResult.Loading)

        val file = File.createTempFile(UUID.randomUUID().toString(), ".jpg")
        sourceFile.copyTo(file, overwrite = true)

        val updatedSettings = renderSettings.copy(filePath = file.absolutePath)

        val previewContainer = renderRepository.preparePreviewContainer(
            dpiX = printProfile.dpix,
            dpiY = printProfile.dpiy,
            filePath = updatedSettings.filePath,
            paperHeightMm = printProfile.height,
            paperWidthMm = printProfile.width,
            printOrientation = updatedSettings.orientation,
            viewWidth = containerSize.width,
            viewHeight = containerSize.height
        )

        val picture = BitmapFactory.decodeFile(updatedSettings.filePath)
        val result = renderRepository.renderBitmap(
            width = printProfile.width,
            height = printProfile.height,
            printWidth = printProfile.printWidth,
            printHeight = printProfile.printHeight,
            marginTop = printProfile.marginTop,
            marginLeft = printProfile.marginLeft,
            dpix = printProfile.dpix,
            dpiy = printProfile.dpiy,
            renderSettingsV2 = updatedSettings.copy(
                canvasWidth = previewContainer.width,
                canvasHeight = previewContainer.height
            ),
            picture = picture,
        )

        result.saveToFile(file)

        val renderResult = RenderResult(
            width = previewContainer.width,
            height = previewContainer.height,
            filePath = file.absolutePath
        )
        emit(FlowResult.Success(renderResult))
    }

    fun prepare(uris: List<Uri>) = flow {
        emit(FlowResult.Loading)

        val files = uris.transformToBitmapFiles(context)
        emit(FlowResult.Success(files))
    }

    fun createJob(
        spotId: String?,
        profileId: String?,
        copies: Int,
        @PrintSize printSize: Int,
        @PrintOrientation orientation: Int,
        sourceFiles: List<File>?
    ) = flow {
        sourceFiles ?: throw IllegalStateException()
        spotId ?: throw IllegalStateException()
        profileId ?: throw IllegalStateException()

        emit(FlowResult.Loading)

        val job = jobRepository.createJob(
            name = "",
            spotId = spotId,
            profileId = profileId,
            copies = copies,
            printSize = printSize,
            printOrientation = orientation,
            sourceFiles = sourceFiles,
            clientName = ""
        )

        SendJobWorker.create(context)
        emit(FlowResult.Success(null))
    }
}

