package theorycrafter.ui

import androidx.compose.foundation.layout.*
import androidx.compose.material.LocalTextStyle
import androidx.compose.material.Snackbar
import androidx.compose.material.SnackbarHostState
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.times
import androidx.compose.ui.window.WindowPosition
import compose.input.KeyShortcut
import compose.input.KeyboardModifierMatcher
import compose.utils.HSpacer
import compose.utils.LocalKeyShortcutsManager
import compose.utils.VSpacer
import compose.utils.VerticallyCenteredRow
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import theorycrafter.*
import theorycrafter.TheorycrafterContext.settings
import theorycrafter.fitting.Fit
import theorycrafter.formats.PyfaDbSelectionDialog
import theorycrafter.formats.loadFitsFromPyfa
import theorycrafter.formats.loadFitsFromXml
import theorycrafter.formats.writeFitsToXml
import theorycrafter.tournaments.CurrentTournamentDescriptor
import theorycrafter.tournaments.toggleUseCurrentTournamentRules
import theorycrafter.ui.fiteditor.FitEditor
import theorycrafter.ui.fiteditor.PackForBattleDialog
import theorycrafter.ui.fitstats.FitStats
import theorycrafter.ui.widgets.ClickableText
import theorycrafter.ui.widgets.LocalStandardDialogs
import theorycrafter.ui.widgets.ThreePanelScaffold
import theorycrafter.utils.LocalIsTest
import theorycrafter.utils.NativeReadFilePickerDialog
import theorycrafter.utils.extensionFilenameFilter
import theorycrafter.utils.thenIf
import java.io.File


/**
 * The content of the main window.
 */
@Composable
fun MainWindowContent() {
    val windowManager = LocalTheorycrafterWindowManager.current
    val fitHandle = windowManager.fitHandleInMainWindow
    var requestFocusForFitEditor by remember { mutableStateOf(false) }

    val fit = fitHandle.loadFit()

    var showCreateNewFitDialog by remember { mutableStateOf(false) }

    var showImportFileSelectionDialog by remember { mutableStateOf(false) }
    var xmlFileToImportFitsFrom: File? by remember { mutableStateOf(null) }
    var showPyfaDbFileSelectionDialog: Boolean by remember { mutableStateOf(false) }
    var pyfaDbFileToImportFitsFrom: File? by remember { mutableStateOf(null) }
    var showExportFitsDialog by remember { mutableStateOf(false) }

    val coroutineScope = rememberCoroutineScope()
    val snackbarHost = remember { SnackbarHostState() }
    val clipboardManager = LocalClipboardManager.current
    val dialogs = LocalStandardDialogs.current

    val fitOpener = remember(windowManager) {
        object: FitOpener {
            override val canOpenFitsInCurrentWindow: Boolean
                get() = true

            override fun openFitInCurrentWindow(fitHandle: FitHandle) {
                windowManager.showFitInMainWindow(fitHandle)
                requestFocusForFitEditor = true
            }

            override fun openFitInSecondaryWindow(fitHandle: FitHandle) {
                windowManager.openFitInSecondaryWindow(fitHandle)
            }
        }
    }

    val onCreateNewFit = { showCreateNewFitDialog = true }

    val onImportFitFromClipboard = remember(fitOpener, clipboardManager, snackbarHost) {
        fun() {
            coroutineScope.launch {
                val result = importFitFromClipboard(clipboardManager, settings.newFitTags())
                if (result.isSuccess)
                    fitOpener.openFitInCurrentWindow(result.value())
                else
                    snackbarHost.showSnackbar(result.failure())
            }
        }
    }

    val onImportFitsFromXmlFile = remember {
        fun() {
            showImportFileSelectionDialog = true
        }
    }

    val onExportFitsToXmlFile = remember {
        fun() {
            showExportFitsDialog = true
        }
    }

    val onImportFitsFromPyfa = remember {
        fun() {
            showPyfaDbFileSelectionDialog = true
        }
    }

    val onDeleteFits = remember(dialogs, coroutineScope) {
        fun(fits: Collection<FitHandle>) {
            dialogs.showConfirmDialog(
                text = if (fits.size == 1){
                    fits.single().let {
                        val shipType = TheorycrafterContext.eveData.shipType(it.shipTypeId)
                        "Delete ${it.name} (${shipType.shortName()})?"
                    }
                }
                else
                    "Delete ${fits.size} fits?",
                confirmText = "Delete",
                onConfirm = {
                    coroutineScope.launch {
                        TheorycrafterContext.fits.delete(fits)
                    }
                },
            )
        }
    }

    CompositionLocalProvider(
        LocalSnackbarHost provides snackbarHost,
        LocalFitOpener provides fitOpener
    ) {
        FitWindowScaffold(
            fitList = {
                FitListPanel(
                    onRenameFit = { fitHandle, name ->
                        coroutineScope.launch {
                            TheorycrafterContext.fits.setName(fitHandle, name)
                        }
                    },
                    onCreateNewFit = onCreateNewFit,
                    onImportFitFromClipboard = onImportFitFromClipboard,
                    onImportFitsFromXmlFile = onImportFitsFromXmlFile,
                    onImportFitsFromPyfa = onImportFitsFromPyfa,
                    onExportFitsToXmlFile = onExportFitsToXmlFile,
                    onDeleteFits = onDeleteFits,
                    displayedFitHandle = fitHandle
                )
            },
            fitEditor = {
                FitEditorOrNone(
                    fitHandle = fitHandle,
                    fit = fit,
                    requestInitialFocus = requestFocusForFitEditor,
                    onCreateNewFit = onCreateNewFit,
                    onImportFitFromClipboard = onImportFitFromClipboard,
                    onImportFitsFromPyfa = onImportFitsFromPyfa,
                    onImportFitsFromXmlFile = onImportFitsFromXmlFile,
                )
            },
            fitStats = {
                FitStatsOrNone(fit)
            },
            statusBar = {
                BottomStatusBar()
            },
            snackbarHostState = snackbarHost
        )

        if (showCreateNewFitDialog) {
            NewFitDialog(
                onDismiss = { showCreateNewFitDialog = false },
                initialTags = settings.newFitTags(),
                createNewFit = { shipType, fitName, tags ->
                    coroutineScope.launch {
                        val newFit = TheorycrafterContext.fits.addEmpty(shipType, fitName, tags)
                        fitOpener.openFitPreferCurrentWindow(newFit)
                    }
                }
            )
        }

        if (showImportFileSelectionDialog) {
            NativeReadFilePickerDialog(
                title = "Select XML fittings file",
                filenameFilter = extensionFilenameFilter(ignoreCase = true, "xml"),
                onCompletedSelecting = { file ->
                    if (file != null)
                        xmlFileToImportFitsFrom = file
                    showImportFileSelectionDialog = false
                }
            )
        }

        if (showExportFitsDialog) {
            ExportFitsDialog(
                onExport = { fitsToExport, exportFile ->
                    val eveData = TheorycrafterContext.eveData
                    coroutineScope.launch(Dispatchers.IO) {
                        exportFile.writer().use { writer ->
                            writeFitsToXml(eveData, fitsToExport, writer)
                        }
                        snackbarHost.showSnackbar("Exported ${fitsToExport.size} fit(s)")
                    }
                    showExportFitsDialog = false
                },
                onDismiss = { 
                    showExportFitsDialog = false
                }
            )
        }

        xmlFileToImportFitsFrom?.let { file ->
            ImportFitsDialog(
                readFits = {
                    file.reader().use { reader ->
                        loadFitsFromXml(
                            eveData = TheorycrafterContext.eveData,
                            reader = reader,
                        )
                    }
                },
                fitsSourceName = file.name,
                warnAboutMutatedItems = true,  // XML may not contain mutated attributes data
                defaultTags = settings.newFitTags(),
                onImport = { importResult, fits ->
                    coroutineScope.launch {
                        TheorycrafterContext.fits.addImportedFits(importResult, fits)
                        snackbarHost.showSnackbar("Imported ${fits.size} fit(s)")
                    }
                },
                onDismiss = { xmlFileToImportFitsFrom = null }
            )
        }


        if (showPyfaDbFileSelectionDialog) {
            PyfaDbSelectionDialog(
                onConfirm = { dbFile ->
                    pyfaDbFileToImportFitsFrom = dbFile
                },
                onDismiss = {
                    showPyfaDbFileSelectionDialog = false
                }
            )
        }

        pyfaDbFileToImportFitsFrom?.let { file ->
            ImportFitsDialog(
                readFits = {
                    loadFitsFromPyfa(TheorycrafterContext.eveData, file)
                },
                fitsSourceName = "Pyfa",
                warnAboutMutatedItems = false,  // Pyfa DB should always contain mutated attributes data
                defaultTags = listOf("pyfa"),
                onImport = { importResult, fits ->
                    coroutineScope.launch {
                        TheorycrafterContext.fits.addImportedFits(importResult, fits)
                        snackbarHost.showSnackbar("Imported ${fits.size} fit(s)")
                    }
                },
                onDismiss = {
                    pyfaDbFileToImportFitsFrom = null
                }
            )
        }

        registerFitWindowActions(
            provideFitHandle = { fitHandle },
            onCreateNewFit = onCreateNewFit,
            onImportFitFromClipboard = onImportFitFromClipboard,
        )
    }

    if (!LocalIsTest.current) {
        OnStartupDialogs()
    }
}


/**
 * Loads the fit of the given [FitHandle] and returns it as a state.
 */
@Composable
private fun FitHandle?.loadFit(): Fit? {
    val dialogs = LocalStandardDialogs.current
    return TheorycrafterContext.fits.rememberEngineFitOf(
        handle = this,
        onError = {
            dialogs.showErrorDialog("Error loading fit ${this!!.name}:\n${it.message}")
            it.printStackTrace()
        }
    )
}


/**
 * The fit editor UI, or a UI saying there is no selected fit.
 */
@Composable
private fun FitEditorOrNone(
    fitHandle: FitHandle?,
    fit: Fit?,
    requestInitialFocus: Boolean,
    onCreateNewFit: (() -> Unit)?,
    onImportFitFromClipboard: (() -> Unit)?,
    onImportFitsFromPyfa: (() -> Unit)?,
    onImportFitsFromXmlFile: (() -> Unit)?,
) {
    val modifier = Modifier.fillMaxSize()
    if (fitHandle == null) {
        NoFitDisplayedScreen(
            modifier = modifier,
            onCreateNewFit = onCreateNewFit,
            onImportFitFromClipboard = onImportFitFromClipboard,
            onImportFitsFromPyfa = onImportFitsFromPyfa,
            onImportFitsFromXmlFile = onImportFitsFromXmlFile
        )
    }
    else if (fit != null) {
        val savedFitState = remember(fit) {
            TheorycrafterContext.fitEditorSavedFitStateFor(fit)
        }

        FitEditor(
            fit = fit,
            fitHandle = fitHandle,
            requestInitialFocus = requestInitialFocus,
            savedFitState = savedFitState,
            modifier = modifier,
        )
    }
}


/**
 * The fit stats UI, or a UI saying there is no selected fit.
 */
@Composable
fun FitStatsOrNone(fit: Fit?, changeKey: Any? = fit) {
    val modifier = Modifier
        .width(TheorycrafterTheme.sizes.fitStatsPanelWidth)
        .fillMaxHeight()

    // Wrapping in key(fit) prevents the resists animation from running when switching between different fits,
    key(changeKey) {
        if (fit == null)
            FitStatsNoFitOpened(modifier)
        else
            FitStats(fit, modifier)
    }
}


/**
 * The UI showing that there is no selected fit.
 */
@Composable
private fun FitStatsNoFitOpened(
    modifier: Modifier
) {
    Box(
        modifier = modifier,
        contentAlignment = Alignment.Center
    ) {
        Text(
            text = "No fit opened",
            modifier = Modifier
                .padding(TheorycrafterTheme.spacing.large),
        )
    }
}


/**
 * The top-level layout for the main and fit windows.
 */
@Composable
fun FitWindowScaffold(


    /**
     * The UI showing the list of fits.
     */
    fitList: (@Composable () -> Unit)?,


    /**
     * The UI for editing the currently selected fit. This includes the title and action button.
     */
    fitEditor: @Composable () -> Unit,


    /**
     * The UI showing the stats of the currently selected fit.
     */
    fitStats: @Composable () -> Unit,


    /**
     * A status bar.
     */
    statusBar: (@Composable () -> Unit)?,


    /**
     * The [SnackbarHostState] to display/use.
     */
    snackbarHostState: SnackbarHostState


) {
    ThreePanelScaffold(
        left = if (fitList == null) null else { ->
            TitledPanel(
                title = "Saved Fits",
                modifier = Modifier.width(TheorycrafterTheme.sizes.savedFitsPanelWidth),
                content = fitList,
            )
        },
        middle = { fitEditor() },
        right = { fitStats() },
        statusBar = if (statusBar == null) null else { -> statusBar() },
        snackbarHostState = snackbarHostState
    )
}


/**
 * The key shortcuts for the main window.
 */
object MainWindowKeyShortcuts {


    /**
     * The key shortcut to focus the fit search field.
     */
    val FocusFitSearchField = KeyShortcut(Key.F, KeyboardModifierMatcher.Command)


    /**
     * The key shortcut to create a new fit.
     */
    val CreateNewFit = KeyShortcut(Key.N, KeyboardModifierMatcher.Command)


    /**
     * The key shortcut to paste a fit from the clipboard.
     */
    val PasteFitFromClipboard = KeyShortcut(Key.V, KeyboardModifierMatcher.shift().cmd())


}


/**
 * The key shortcuts for the fit windows.
 */
object FitWindowKeyShortcuts {


    /**
     * The key shortcut to copy the currently displayed fit to the clipboard.
     */
    val CopyFitToClipboard = KeyShortcut(Key.C, KeyboardModifierMatcher.shift().cmd())


    /**
     * The key shortcut to copy the currently displayed fit to the clipboard, after selecting export options.
     */
    val CopyFitWithOptionsToClipboard = KeyShortcut(Key.C, KeyboardModifierMatcher.alt().cmd())


    /**
     * The key shortcut to toggle applying the active tournament rules.
     */
    val ToggleUseTournamentRules = KeyShortcut(Key.T, KeyboardModifierMatcher.shift().cmd())


    /**
     * The key shortcut to show the [PackForBattleDialog].
     */
    val ShowPackForBattleDialog = KeyShortcut(Key.P, KeyboardModifierMatcher.cmd())


    /**
     * The key shortcut to optimize a fit.
     */
    val OptimizeFit = KeyShortcut(Key.O, KeyboardModifierMatcher.cmd())


    /**
     * The key shortcut to show the graphs window.
     */
    val ShowGraphsWindow = KeyShortcut(Key.G, KeyboardModifierMatcher.cmd())


    /**
     * The key shortcut to show the market window.
     */
    val ShowMarketWindow = KeyShortcut(Key.M, KeyboardModifierMatcher.cmd())


    /**
     * The key shortcut to show the doctrines window.
     */
    val ShowDoctrinesWindow = KeyShortcut(Key.D, KeyboardModifierMatcher.cmd())


}


/**
 * Registers the fit-related actions in the main or fit window.
 */
@Composable
private fun registerFitWindowActions(
    provideFitHandle: () -> FitHandle?,
    onCreateNewFit: (() -> Unit)?,
    onImportFitFromClipboard: (() -> Unit)?,
) {
    if (onCreateNewFit != null)
        registerCreateNewFitAction(onCreateNewFit)
    registerCopyFitToClipboardActions(provideFitHandle)
    if (onImportFitFromClipboard != null)
        registerPasteFitAction(onImportFitFromClipboard)
    registerToggleActiveTournamentAction()
    registerShowGraphWindowAction()
    registerShowMarketWindowAction()
}


/**
 * Registers the window shortcut to create a new fit.
 */
@Composable
private fun registerCreateNewFitAction(action: () -> Unit) {
    LocalKeyShortcutsManager.current.register(
        shortcut = MainWindowKeyShortcuts.CreateNewFit,
        action = action
    )
}


/**
 * Registers the window shortcuts to copy a fit to the clipboard.
 */
@Composable
private fun registerCopyFitToClipboardActions(fitHandle: () -> FitHandle?) {
    val fitCopier = rememberFitCopier()
    with(LocalKeyShortcutsManager.current) {
        register(FitWindowKeyShortcuts.CopyFitToClipboard) {
            fitHandle()?.let { fitCopier.copy(it) }
        }
        register(FitWindowKeyShortcuts.CopyFitWithOptionsToClipboard) {
            fitHandle()?.let { fitCopier.copyWithOptions(it) }
        }
    }
}


/**
 * Registers the window shortcut to paste a fit from the clipboard.
 */
@Composable
private fun registerPasteFitAction(action: () -> Unit) {
    LocalKeyShortcutsManager.current.register(
        shortcut = MainWindowKeyShortcuts.PasteFitFromClipboard,
        action = action
    )
}


/**
 * Registers the window shortcut to toggle the active tournament.
 */
@Composable
private fun registerToggleActiveTournamentAction() {
    if (CurrentTournamentDescriptor != null) {
        LocalKeyShortcutsManager.current.register(FitWindowKeyShortcuts.ToggleUseTournamentRules) {
            toggleUseCurrentTournamentRules()
        }
    }
}


/**
 * Registers the window shortcut to show the graph window.
 */
@Composable
private fun registerShowGraphWindowAction() {
    val windowManager = LocalTheorycrafterWindowManager.current
    LocalKeyShortcutsManager.current.register(FitWindowKeyShortcuts.ShowGraphsWindow) {
        windowManager.showGraphsWindow()
    }
}


/**
 * Registers the window shortcut to show the market window.
 */
@Composable
private fun registerShowMarketWindowAction() {
    val windowManager = LocalTheorycrafterWindowManager.current
    LocalKeyShortcutsManager.current.register(FitWindowKeyShortcuts.ShowMarketWindow) {
        windowManager.showMarketTreeWindow()
    }
}


/**
 * A panel with a title.
 */
@Composable
fun TitledPanel(
    title: String,
    titleTestTag: String? = null,
    modifier: Modifier = Modifier,
    actionsButton: @Composable (() -> Unit)? = null,
    content: @Composable () -> Unit,
) {
    TitledPanel(
        title = {
            Text(
                text = title,
                modifier = Modifier
                    .thenIf(titleTestTag != null) { testTag(titleTestTag!!) }
            )
        },
        modifier = modifier,
        actionsButton = actionsButton,
        content = content
    )
}


/**
 * A panel with a title.
 */
@Composable
fun TitledPanel(
    title: @Composable () -> Unit,
    modifier: Modifier = Modifier,
    actionsButton: @Composable (() -> Unit)? = null,
    content: @Composable () -> Unit,
) {
    Column(
        modifier = modifier
    ) {
        VerticallyCenteredRow(
            modifier = Modifier
                .fillMaxWidth()
                .padding(top = TheorycrafterTheme.spacing.verticalEdgeMargin)
                .padding(start = TheorycrafterTheme.spacing.horizontalEdgeMargin)
                .heightIn(
                    // Must be at least as tall as FitActionsButton so the height is consistent
                    min = Icons.MenuImageVector.defaultHeight + 2 * TheorycrafterTheme.spacing.actionsButtonIconPadding
                ),
        ) {
            Box(Modifier.weight(1f)) {  // Weight so it doesn't push out the button
                CompositionLocalProvider(LocalTextStyle provides TheorycrafterTheme.textStyles.largeHeading) {
                    title()
                }
            }

            HSpacer(TheorycrafterTheme.spacing.horizontalEdgeMargin)

            if (actionsButton != null) {
                actionsButton()
            }
        }
        content()
    }
}


/**
 * Displays the individual fit windows.
 */
@Composable
fun FitWindows() {
    val windowManager = LocalTheorycrafterWindowManager.current
    for ((index, settings) in windowManager.openSecondaryFitWindowSettings.withIndex()) {
        key(settings) {
            FitWindow(settings, index)
        }
    }
}


/**
 * Returns the title to show when displaying the given fit handle.
 */
private fun FitHandle.windowTitle(): String {
    val ship = TheorycrafterContext.eveData.shipType(shipTypeId)
    return "$name  ·  ${ship.name}"
}


/**
 * The minimum size of secondary fit windows.
 */
private val FitWindowMinimumSize = DpSize(1000.dp, 500.dp)


/**
 * The secondary fit window with the given settings.
 */
@Composable
private fun FitWindow(windowSettings: TheorycrafterSettings.FitWindowSettings, index: Int) {
    val fitHandle = windowSettings.requireFitHandle()
    val windowManager = LocalTheorycrafterWindowManager.current

    fun closeWindow() = windowManager.closeSecondaryFitWindow(fitHandle)

    val windowState = rememberWindowStateAndUpdateSettings(
        windowSettings = windowSettings,
        defaultPosition = { defaultFitWindowPosition(windowManager, index) },
        defaultSize = { TheorycrafterTheme.sizes.fitWindowDefaultSize },
        minimumSize = FitWindowMinimumSize
    )

    TheorycrafterWindow(
        onCloseRequest = ::closeWindow,
        title = fitHandle.windowTitle(),
        state = windowState,
        minimumSize = FitWindowMinimumSize
    ) {
        FitWindowContent(fitHandle)

        LaunchedEffect(windowManager, fitHandle, window) {
            windowManager.registerSecondaryFitWindow(fitHandle, window)
        }
    }
}


/**
 * Returns the default position where a new fit window should be opened, when it's not already provided by settings.
 */
private fun defaultFitWindowPosition(
    windowManager: TheorycrafterWindowManager,
    index: Int
): WindowPosition {
    val mainWindowPosition = windowManager.mainWindowState.position

    val x = mainWindowPosition.x + (index + 1) * 40.dp
    val y = mainWindowPosition.y + (index + 1) * 40.dp

    return WindowPosition(x = x, y = y)
}


/**
 * The content of the fit window.
 */
@Composable
private fun FitWindowContent(fitHandle: FitHandle) {
    val fit = fitHandle.loadFit()

    val snackbarHost = remember { SnackbarHostState() }
    CompositionLocalProvider(LocalSnackbarHost provides snackbarHost) {
        FitWindowScaffold(
            fitList = null,
            fitEditor = {
                FitEditorOrNone(
                    fitHandle = fitHandle,
                    fit = fit,
                    requestInitialFocus = true,
                    // The fit handle is never null, so these actions aren't needed
                    onCreateNewFit = null,
                    onImportFitFromClipboard = null,
                    onImportFitsFromPyfa = null,
                    onImportFitsFromXmlFile = null
                )
            },
            fitStats = {
                FitStatsOrNone(fit)
            },
            statusBar = null,
            snackbarHostState = snackbarHost
        )

        registerFitWindowActions(
            provideFitHandle = { fitHandle },
            onCreateNewFit = null,
            onImportFitFromClipboard = null,
        )
    }
}


/**
 * The provider of the ability to display a [Snackbar].
 */
val LocalSnackbarHost = staticCompositionLocalOf<SnackbarHostState>{ error("Missing Snackbar") }


/**
 * The interface for objects that can open a fits.
 */
interface FitOpener {


    /**
     * Whether this [FitOpener] can open fits in the current window.
     * If this is `false`, [openFitInCurrentWindow] should not be called.
     */
    val canOpenFitsInCurrentWindow: Boolean


    /**
     * Opens the given fit handle in the current (for the caller) window.
     */
    fun openFitInCurrentWindow(fitHandle: FitHandle)


    /**
     * Opens the given fit in a secondary window.
     */
    fun openFitInSecondaryWindow(fitHandle: FitHandle)


    /**
     * If possible, opens the fit in the current window; otherwise opens it in a secondary window.
     */
    fun openFitPreferCurrentWindow(fitHandle: FitHandle) =
        if (canOpenFitsInCurrentWindow)
            openFitInCurrentWindow(fitHandle)
        else
            openFitInSecondaryWindow(fitHandle)

}


/**
 * A [FitOpener] that can only open fits in a new window.
 */
class FitOpenerInNewWindowOnly(val windowManager: TheorycrafterWindowManager): FitOpener {

    override val canOpenFitsInCurrentWindow: Boolean
        get() = false

    override fun openFitInCurrentWindow(fitHandle: FitHandle) {
        error("Can't open fit in current window")
    }

    override fun openFitInSecondaryWindow(fitHandle: FitHandle) {
        windowManager.openFitInSecondaryWindow(fitHandle)
    }

}


/**
 * The composition local [FitOpener].
 */
val LocalFitOpener = staticCompositionLocalOf<FitOpener> { error("Missing FitOpener") }


/**
 * Displayed in place of the fit editor when no fit is displayed.
 *
 * Shows some common initial actions a user may want to do.
 */
@Composable
private fun NoFitDisplayedScreen(
    modifier: Modifier,
    onCreateNewFit: (() -> Unit)?,
    onImportFitFromClipboard: (() -> Unit)?,
    onImportFitsFromPyfa: (() -> Unit)?,
    onImportFitsFromXmlFile: (() -> Unit)?,
) {
    Box(
        modifier = modifier,
        contentAlignment = Alignment.Center,
    ) {
        Column(
            verticalArrangement = Arrangement.spacedBy(TheorycrafterTheme.spacing.small),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(
                text = "No fit opened",
                style = TheorycrafterTheme.textStyles.largeHeading,
                modifier = Modifier
                    .padding(TheorycrafterTheme.spacing.large),
            )

            VSpacer(TheorycrafterTheme.spacing.small)

            if (onCreateNewFit != null) {
                ClickableText(
                    text = "Create new fit (${MainWindowKeyShortcuts.CreateNewFit})",
                    onClick = onCreateNewFit
                )
            }
            if (onImportFitFromClipboard != null) {
                ClickableText(
                    text = "Paste fit from clipboard (${MainWindowKeyShortcuts.PasteFitFromClipboard})",
                    onClick = onImportFitFromClipboard,
                )
            }
            if (onImportFitsFromPyfa != null) {
                ClickableText(
                    text = "Import fits from Pyfa",
                    onClick = onImportFitsFromPyfa
                )
            }
            if (onImportFitsFromXmlFile != null) {
                ClickableText(
                    text = "Import fits from XML file",
                    onClick = onImportFitsFromXmlFile
                )
            }

            val windowManager = LocalTheorycrafterWindowManager.current
            ClickableText(
                text = "Open settings",
                onClick = {
                    windowManager.showSettingsWindow()
                }
            )
        }
    }
}
