package theorycrafter.ui

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.width
import androidx.compose.material.SnackbarHostState
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ClipboardManager
import androidx.compose.ui.platform.LocalClipboardManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import theorycrafter.FitExportOptionSettings
import theorycrafter.FitHandle
import theorycrafter.TheorycrafterContext
import theorycrafter.formats.EftExportOptions
import theorycrafter.formats.fitFromEft
import theorycrafter.formats.toEft
import theorycrafter.ui.widgets.CheckboxedText
import theorycrafter.ui.widgets.DialogInitiallyFocusedButton
import theorycrafter.ui.widgets.InnerDialog
import theorycrafter.utils.ValueOrError
import theorycrafter.utils.setText


/**
 * An object that can copy fits to the clipboard.
 */
@Stable
class FitCopier(
    private val clipboardManager: ClipboardManager,
    private val snackbarHost: SnackbarHostState,
    private val coroutineScope: CoroutineScope,
) {


    /**
     * The fit handle for which the export options dialog is being shown.
     */
    private var fitHandleToExportWithOptions: FitHandle? by mutableStateOf(null)


    /**
     * Copies the given fit to the clipboard.
     */
    fun copy(fitHandle: FitHandle, options: FitExportOptions? = null) {
        val actualOptions = options ?: TheorycrafterContext.settings.regularFitExportOptions.toFitExportOptions()
        with(TheorycrafterContext.eveData) {
            val fit = TheorycrafterContext.fits.storedFitOf(fitHandle)
            val shipType = shipType(fit.shipTypeId)
            val text = when (actualOptions) {
                is FitExportOptions.Eft -> fit.toEft(actualOptions.eftOptions)
            }
            clipboardManager.setText(text)
            coroutineScope.launch {
                snackbarHost.showSnackbar("Copied \"${fitHandle.name}\" (${shipType.name}) to clipboard")
            }
        }
    }


    /**
     * Copies the given fit to the clipboard, after letting the user specify export options.
     */
    fun copyWithOptions(fitHandle: FitHandle) {
        fitHandleToExportWithOptions = fitHandle
    }


    /**
     * A composable to put somewhere in order to let the [FitCopier] show the options dialog.
     */
    @Composable
    fun content() {
        fitHandleToExportWithOptions?.let { fitHandle ->
            val settings = TheorycrafterContext.settings
            FitExportOptionsDialog(
                exportOptionSettings = settings.fitExportOptionsDialogValues,
                onExportOptionsChanged = {
                    settings.fitExportOptionsDialogValues = it
                },
                onDismiss = { fitHandleToExportWithOptions = null },
                confirmText = "Copy to Clipboard",
                onConfirm = { copy(fitHandle, it) }
            )
        }
    }


}


/**
 * Creates a remembered [FitCopier] for the calling compose context.
 */
@Composable
fun rememberFitCopier(): FitCopier {
    val clipboardManager = LocalClipboardManager.current
    val snackbarHost = LocalSnackbarHost.current
    val coroutineScope = rememberCoroutineScope()

    val fitCopier = remember(clipboardManager, snackbarHost, coroutineScope) {
        FitCopier(clipboardManager, snackbarHost, coroutineScope)
    }
    fitCopier.content()

    return fitCopier
}


/**
 * UI for editing [FitExportOptionSettings].
 */
@Composable
fun FitExportOptionsEditor(
    exportOptionSettings: FitExportOptionSettings,
    onExportOptionsChanged: (FitExportOptionSettings) -> Unit,
) {
    val eftExportOptions = exportOptionSettings.eftExportOptions

    fun setEftExportOptions(options: EftExportOptions) {
        onExportOptionsChanged(FitExportOptionSettings(options))
    }

    Column(Modifier.width(IntrinsicSize.Max)) {
        CheckboxedText(
            text = "Loaded Charges",
            checked = eftExportOptions.loadedCharges,
            onCheckedChange = {
                setEftExportOptions(eftExportOptions.copy(loadedCharges = it))
            },
            modifier = Modifier.fillMaxWidth()
        )
        CheckboxedText(
            text = "Implants",
            checked = eftExportOptions.implants,
            onCheckedChange = {
                setEftExportOptions(eftExportOptions.copy(implants = it))
            },
            modifier = Modifier.fillMaxWidth()
        )
        CheckboxedText(
            text = "Boosters",
            checked = eftExportOptions.boosters,
            onCheckedChange = {
                setEftExportOptions(eftExportOptions.copy(boosters = it))
            },
            modifier = Modifier.fillMaxWidth()
        )
        CheckboxedText(
            text = "Cargo",
            checked = eftExportOptions.cargo,
            onCheckedChange = {
                setEftExportOptions(eftExportOptions.copy(cargo = it))
            },
            modifier = Modifier.fillMaxWidth()
        )
        CheckboxedText(
            text = "Mutated Attributes",
            checked = eftExportOptions.mutatedAttributes,
            onCheckedChange = {
                setEftExportOptions(eftExportOptions.copy(mutatedAttributes = it))
            },
            modifier = Modifier.fillMaxWidth()
        )
    }
}


/**
 * The dialog to let the user select fit export options.
 */
@Composable
private fun FitExportOptionsDialog(
    exportOptionSettings: FitExportOptionSettings,
    onExportOptionsChanged: (FitExportOptionSettings) -> Unit,
    onDismiss: () -> Unit,
    confirmText: String,
    onConfirm: (FitExportOptions) -> Unit,
) {

    InnerDialog(
        title = "Include:",
        onDismiss = onDismiss,
        confirmText = confirmText,
        initiallyFocusedButton = DialogInitiallyFocusedButton.Confirm,
        onConfirm = {
            onConfirm(exportOptionSettings.toFitExportOptions())
        }
    ) {
        FitExportOptionsEditor(
            exportOptionSettings = exportOptionSettings,
            onExportOptionsChanged = onExportOptionsChanged
        )
    }
}


/**
 * Fit export options.
 */
sealed class FitExportOptions {

    /**
     * The options when exporting in EFT format.
     */
    class Eft(val eftOptions: EftExportOptions): FitExportOptions()

}


/**
 * Returns the [FitExportOptions] for the given [FitExportOptionSettings].
 */
fun FitExportOptionSettings.toFitExportOptions() = FitExportOptions.Eft(eftExportOptions)


/**
 * Imports a fit from the clipboard and returns its [FitHandle], or an error message.
 */
suspend fun importFitFromClipboard(clipboardManager: ClipboardManager): ValueOrError<FitHandle, String> {
    val clipboardText = clipboardManager.getText()
    if (clipboardText == null)
        return ValueOrError.failure("No text in the clipboard")

    val fit = with(TheorycrafterContext.eveData) { fitFromEft(clipboardText.text) }
    if (fit == null)
        return ValueOrError.failure("Clipboard doesn't contain a valid fit.\nSupported formats: EFT")

    val fitHandle = TheorycrafterContext.fits.add(fit)
    return ValueOrError.success(fitHandle)
}
