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.LocalClipboard
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.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import theorycrafter.*
import theorycrafter.TheorycrafterContext.settings
import theorycrafter.fits.FitHandle
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 clipboard = LocalClipboard.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, clipboard, snackbarHost) {
        fun() {
            coroutineScope.launch {
                val result = importFitFromClipboard(clipboard, 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.alt().cmd())


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


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


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


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


}


/**
 * Registers the fit-related actions in the main or fit window.
 */
@Composable
private fun registerFitWindowActions(
    provideFitHandle: () -> FitHandle?,
    onCreateNewFit: (() -> Unit)?,
    onImportFitFromClipboard: (() -> Unit)?,
) {
    val shortcutsManager = LocalKeyShortcutsManager.current

    if (onCreateNewFit != null) {
        shortcutsManager.register(MainWindowKeyShortcuts.CreateNewFit, onCreateNewFit)
    }
    shortcutsManager.registerCopyFitToClipboardActions(provideFitHandle)
    if (onImportFitFromClipboard != null) {
        shortcutsManager.register(MainWindowKeyShortcuts.PasteFitFromClipboard, onImportFitFromClipboard)
    }
    shortcutsManager.registerToggleActiveTournamentAction()
    shortcutsManager.registerShowoToolWindowsActions()
}


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


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


/**
 * Registers the shortcuts that open various windows.
 */
@Composable
private fun KeyShortcutsManager.registerShowoToolWindowsActions() {
    val windowManager = LocalTheorycrafterWindowManager.current

    register(FitWindowKeyShortcuts.ShowDoctrinesWindow) {
        windowManager.showDoctrinesWindow()
    }
    register(FitWindowKeyShortcuts.ShowGraphsWindow) {
        windowManager.showGraphsWindow()
    }
    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()
                }
            )
        }
    }
}
