/*
 * Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
 */

package at.bitfire.synctools.mapping.tasks

import android.content.Entity
import at.bitfire.synctools.icalendar.AssociatedTasks
import at.bitfire.synctools.icalendar.withUserAgents
import at.bitfire.synctools.mapping.tasks.handler.AlarmsHandler
import at.bitfire.synctools.mapping.tasks.handler.CategoriesHandler
import at.bitfire.synctools.mapping.tasks.handler.ClassificationHandler
import at.bitfire.synctools.mapping.tasks.handler.ColorHandler
import at.bitfire.synctools.mapping.tasks.handler.CommentsHandler
import at.bitfire.synctools.mapping.tasks.handler.CompletedHandler
import at.bitfire.synctools.mapping.tasks.handler.DescriptionHandler
import at.bitfire.synctools.mapping.tasks.handler.DmfsTaskEntityHandler
import at.bitfire.synctools.mapping.tasks.handler.DueHandler
import at.bitfire.synctools.mapping.tasks.handler.DurationHandler
import at.bitfire.synctools.mapping.tasks.handler.GeoHandler
import at.bitfire.synctools.mapping.tasks.handler.LocationHandler
import at.bitfire.synctools.mapping.tasks.handler.OrganizerHandler
import at.bitfire.synctools.mapping.tasks.handler.PercentCompleteHandler
import at.bitfire.synctools.mapping.tasks.handler.PriorityHandler
import at.bitfire.synctools.mapping.tasks.handler.RecurrenceFieldsHandler
import at.bitfire.synctools.mapping.tasks.handler.RelationsHandler
import at.bitfire.synctools.mapping.tasks.handler.SequenceHandler
import at.bitfire.synctools.mapping.tasks.handler.StartTimeHandler
import at.bitfire.synctools.mapping.tasks.handler.StatusHandler
import at.bitfire.synctools.mapping.tasks.handler.TitleHandler
import at.bitfire.synctools.mapping.tasks.handler.UidHandler
import at.bitfire.synctools.mapping.tasks.handler.UnknownPropertiesHandler
import at.bitfire.synctools.mapping.tasks.handler.UrlHandler
import at.bitfire.synctools.storage.TaskProvider
import at.bitfire.synctools.storage.tasks.TaskAndExceptions
import net.fortuna.ical4j.model.component.VToDo
import net.fortuna.ical4j.model.property.ProdId
import org.dmfs.tasks.contract.TaskContract
import java.util.UUID

class DmfsTaskHandler(
    private val prodId: ProdId,
    private val providerName: TaskProvider.ProviderName
) {
    private val entityHandlers = arrayOf<DmfsTaskEntityHandler>(
        UidHandler(),
        TitleHandler(),
        SequenceHandler(),
        StartTimeHandler(),
        DueHandler(),
        DurationHandler(),
        DescriptionHandler(),
        LocationHandler(),
        GeoHandler(),
        ColorHandler(),
        UrlHandler(),
        OrganizerHandler(),
        PriorityHandler(),
        ClassificationHandler(),
        StatusHandler(),
        CompletedHandler(),
        PercentCompleteHandler(),
        RecurrenceFieldsHandler(),
        AlarmsHandler(),
        CategoriesHandler(),
        CommentsHandler(),
        RelationsHandler(),
        UnknownPropertiesHandler(),
    )

    /**
     * Result of the [mapToVToDos] operation.
     *
     * @param associatedTasks  mapped tasks
     * @param uid              UID of the mapped tasks
     * @param generatedUid     whether [uid] was generated by [mapToVToDos] (*false*: `UID` was already present before mapping)
     */
    class MappingResult(
        val associatedTasks: AssociatedTasks,
        val uid: String,
        val generatedUid: Boolean
    )

    fun mapToVToDos(taskAndExceptions: TaskAndExceptions): MappingResult {
        // make sure that main task has a UID
        var generatedUid = false
        val mainValues = taskAndExceptions.main.entityValues
        val uid = mainValues.getAsString(TaskContract.Tasks._UID) ?: run {
            val newUid = UUID.randomUUID().toString()
            mainValues.put(TaskContract.Tasks._UID, newUid)
            generatedUid = true
            newUid
        }

         // map main task
        val main = mapTask(
            entity = taskAndExceptions.main,
            main = taskAndExceptions.main
        )

        // Exceptions are currently not supported by the mapping code
        val exceptions = listOf<VToDo>()

        val mappedTasks = AssociatedTasks(
            main = main,
            exceptions = exceptions,
            prodId = prodId.withUserAgents(listOf(providerName.packageName))
        )

        return MappingResult(
            associatedTasks = mappedTasks,
            uid = uid,
            generatedUid = generatedUid
        )
    }

    private fun mapTask(entity: Entity, main: Entity): VToDo {
        // initialization adds DTSTAMP
        val vToDo = VToDo(/* initialise = */ true)

        for (handler in entityHandlers) {
            handler.process(from = entity, main = main, to = vToDo)
        }

        return vToDo
    }
}

internal val Entity.NamedContentValues.mimeType: String?
    get() = values.getAsString(TaskContract.Properties.MIMETYPE)
