# Authors: The MNE-Python contributors.
# License: BSD-3-Clause
# Copyright the MNE-Python contributors.

from ..utils import get_config, verbose


@verbose
def coregistration(
    *,
    width=None,
    height=None,
    inst=None,
    subject=None,
    subjects_dir=None,
    head_opacity=None,
    head_high_res=None,
    trans=None,
    orient_to_surface=None,
    scale_by_distance=None,
    mark_inside=None,
    interaction=None,
    fullscreen=None,
    show=True,
    block=False,
    verbose=None,
):
    """Coregister an MRI with a subject's head shape.

    The GUI can be launched through the command line interface:

    .. code-block::  bash

        $ mne coreg

    or using a python interpreter as shown in :ref:`tut-source-alignment`.

    Parameters
    ----------
    width : int | None
        Specify the width for window (in logical pixels).
        Default is None, which uses ``MNE_COREG_WINDOW_WIDTH`` config value
        (which defaults to 800).
    height : int | None
        Specify a height for window (in logical pixels).
        Default is None, which uses ``MNE_COREG_WINDOW_WIDTH`` config value
        (which defaults to 400).
    inst : None | str
        Path to an instance file containing the digitizer data. Compatible for
        Raw, Epochs, and Evoked files.
    subject : None | str
        Name of the mri subject.
    %(subjects_dir)s
    head_opacity : float | None
        The opacity of the head surface in the range [0., 1.].
        Default is None, which uses ``MNE_COREG_HEAD_OPACITY`` config value
        (which defaults to 1.).
    head_high_res : bool | None
        Use a high resolution head surface.
        Default is None, which uses ``MNE_COREG_HEAD_HIGH_RES`` config value
        (which defaults to True).
    trans : path-like | None
        The transform file to use.
    orient_to_surface : bool | None
        If True (default), orient EEG electrode and head shape points
        to the head surface.

        .. versionadded:: 0.16
    scale_by_distance : bool | None
        If True (default), scale the digitization points by their
        distance from the scalp surface.

        .. versionadded:: 0.16
    mark_inside : bool | None
        If True (default), mark points inside the head surface in a
        different color.

        .. versionadded:: 0.16
    %(interaction_scene_none)s
        Defaults to ``'terrain'``.

        .. versionadded:: 0.16
        .. versionchanged:: 1.0
           Default interaction mode if ``None`` and no config setting found
           changed from ``'trackball'`` to ``'terrain'``.
    %(fullscreen)s
        Default is None, which uses ``MNE_COREG_FULLSCREEN`` config value
        (which defaults to False).

        .. versionadded:: 1.1
    show : bool
        Show the GUI if True.
    block : bool
        Whether to halt program execution until the figure is closed.
    %(verbose)s

    Returns
    -------
    frame : instance of CoregistrationUI
        The coregistration frame.

    Notes
    -----
    Many parameters (e.g., ``head_opacity``) take None as a parameter,
    which means that the default will be read from the MNE-Python
    configuration file (which gets saved when exiting).

    Step by step instructions for the coregistrations are shown below:

    .. youtube:: ALV5qqMHLlQ
    """
    config = get_config()
    if head_high_res is None:
        head_high_res = config.get("MNE_COREG_HEAD_HIGH_RES", "true") == "true"
    if head_opacity is None:
        head_opacity = config.get("MNE_COREG_HEAD_OPACITY", 0.8)
    if width is None:
        width = config.get("MNE_COREG_WINDOW_WIDTH", 800)
    if height is None:
        height = config.get("MNE_COREG_WINDOW_HEIGHT", 600)
    if subjects_dir is None:
        if "SUBJECTS_DIR" in config:
            subjects_dir = config["SUBJECTS_DIR"]
        elif "MNE_COREG_SUBJECTS_DIR" in config:
            subjects_dir = config["MNE_COREG_SUBJECTS_DIR"]
    false_like = ("false", "0")
    if orient_to_surface is None:
        orient_to_surface = config.get("MNE_COREG_ORIENT_TO_SURFACE", "true").lower()
        orient_to_surface = orient_to_surface not in false_like
    if scale_by_distance is None:
        scale_by_distance = config.get("MNE_COREG_SCALE_BY_DISTANCE", "true").lower()
        scale_by_distance = scale_by_distance not in false_like
    if interaction is None:
        interaction = config.get("MNE_COREG_INTERACTION", "terrain")
    if mark_inside is None:
        mark_inside = config.get("MNE_COREG_MARK_INSIDE", "true").lower()
        mark_inside = mark_inside not in false_like
    if fullscreen is None:
        fullscreen = config.get("MNE_COREG_FULLSCREEN", "") == "true"
    head_opacity = float(head_opacity)
    width = int(width)
    height = int(height)

    from ..viz.backends.renderer import MNE_3D_BACKEND_TESTING
    from ._coreg import CoregistrationUI

    if MNE_3D_BACKEND_TESTING:
        show = block = False
    return CoregistrationUI(
        info_file=inst,
        subject=subject,
        subjects_dir=subjects_dir,
        head_resolution=head_high_res,
        head_opacity=head_opacity,
        orient_glyphs=orient_to_surface,
        scale_by_distance=scale_by_distance,
        mark_inside=mark_inside,
        trans=trans,
        size=(width, height),
        show=show,
        block=block,
        interaction=interaction,
        fullscreen=fullscreen,
        verbose=verbose,
    )


class _GUIScraper:
    """Scrape GUI outputs."""

    def __repr__(self):
        return "<GUIScraper>"

    def __call__(self, block, block_vars, gallery_conf):
        from ._coreg import CoregistrationUI

        gui_classes = (CoregistrationUI,)
        try:
            from mne_gui_addons._ieeg_locate import (
                IntracranialElectrodeLocator,
            )
        except Exception:
            pass
        else:
            gui_classes = gui_classes + (IntracranialElectrodeLocator,)
        from qtpy import QtGui
        from sphinx_gallery.scrapers import figure_rst

        for gui in block_vars["example_globals"].values():
            if (
                isinstance(gui, gui_classes)
                and not getattr(gui, "_scraped", False)
                and gallery_conf["builder_name"] == "html"
            ):
                gui._scraped = True  # monkey-patch but it's easy enough
                img_fname = next(block_vars["image_path_iterator"])
                # TODO fix in window refactor
                window = gui if hasattr(gui, "grab") else gui._renderer._window
                # window is QWindow
                # https://doc.qt.io/qt-5/qwidget.html#grab
                pixmap = window.grab()
                if hasattr(gui, "_renderer"):  # if no renderer, no need
                    # Now the tricky part: we need to get the 3D renderer,
                    # extract the image from it, and put it in the correct
                    # place in the pixmap. The easiest way to do this is
                    # actually to save the 3D image first, then load it
                    # using QPixmap and Qt geometry.
                    plotter = gui._renderer.plotter
                    plotter.screenshot(img_fname)
                    sub_pixmap = QtGui.QPixmap(img_fname)
                    # https://doc.qt.io/qt-5/qwidget.html#mapTo
                    # https://doc.qt.io/qt-5/qpainter.html#drawPixmap-1
                    QtGui.QPainter(pixmap).drawPixmap(
                        plotter.mapTo(window, plotter.rect().topLeft()), sub_pixmap
                    )
                # https://doc.qt.io/qt-5/qpixmap.html#save
                pixmap.save(img_fname)
                try:  # for compatibility with both GUIs, will be refactored
                    gui._renderer.close()  # TODO should be triggered by close
                except Exception:
                    pass
                gui.close()
                return figure_rst([img_fname], gallery_conf["src_dir"], "GUI")
        return ""
