from __future__ import annotations

from pathlib import Path

from numpy import c_

from nmreval.io.graceeditor import GraceEditor
from nmreval.utils.text import convert

from ..Qt import QtGui, QtCore, QtPrintSupport


class GraceExporter:
    def __init__(self, kwargs: dict):
        self.__agr = None
        self.__opts = kwargs

    def export(self, outfile: str | Path, mode: int | str = 'w'):
        if mode == 'w':
            self.__agr = GraceEditor()
        else:
            self.__agr = GraceEditor(outfile)

        if isinstance(mode, str):
            new_g = self.__agr.new_graph()

            new_g.set_limits(x=self.__opts['limits'][0], y=self.__opts['limits'][1])
            new_g.set_log(x=self.__opts['log'][0], y=self.__opts['log'][1])

            new_g.set_onoff('legend', self.__opts['legend'])
            new_g.set_property(**{
                'title': f'"{convert(self.__opts["labels"][2], old="html", new="agr")}"',
                'legend loctype': 'view',
                'legend': ', '.join(str(i) for i in new_g.world_to_view(self.__opts['legend_pos']))
            })

            for i, ax in enumerate('xy'):
                new_g.set_axis_property(ax, **{
                    'label': f'"{convert(self.__opts["labels"][i], old="html", new="agr")}"',
                    'tick major': self.__opts['ticks'][i][0],
                    'tick minor ticks': self.__opts['ticks'][i][1],
                    'invert': 'on' if self.__opts['invert'][i] else 'off',
                })
                new_g.set_axis_onoff(ax, 'tick major grid', self.__opts['grid'])
            g_idx = new_g.idx
        else:
            g_idx = mode

        colors = self.__agr.colors

        new_colors = []
        for plot_label, item in zip(self.__opts['in_legend'], self.__opts['items']):
            new_s = self.__agr.new_set(g_idx)

            sc = item['symbolcolor']
            c_num = -1
            for i, (_, rgb) in colors.items():
                if rgb == sc:
                    c_num = i
                    break

            if c_num == -1:
                c_num = max(colors.keys())+1
                colors[c_num] = (f'color{c_num}', sc)
                new_colors.append((c_num, f'color{c_num}', sc))

            new_s.set_symbol(**{
                'symbol': item['symbol'].value,
                'size': item['symbolsize'] / 10.,
                'color': c_num,
                'fill color': c_num,
                'fill pattern': 1
            })
            new_s.set_onoff('errorbar', self.__opts['plots'][2])

            lc = item['linecolor']
            c_num = -1
            for c_num, (_, rgb) in colors.items():
                if rgb == lc:
                    break

            if c_num == -1:
                c_num = max(colors.keys())
                colors[c_num + 1] = ()
                new_colors.append((c_num, f'color{c_num + 1}', sc))

            new_s.set_line(**{
                'color': c_num,
                'linewidth': item['linewidth'],
                'linestyle': item['linestyle'].to_agr()
            })

            if plot_label:
                new_s.set_property(
                    comment=f'"{item["name"]}"',
                    legend=f'"{convert(item["name"], old="tex", new="agr")}"'
                )
            else:
                new_s.set_property(comment=f'"{item["name"]}"')

            data = self.__agr.dataset(g_idx, new_s.idx)
            if 'yerr' in item:
                data.type = 'xydy'
                data.data = c_[item['x'], item['y'], item['yerr']]
                new_s.set_property(**{'errorbar color': c_num})
            else:
                data.data = c_[item['x'], item['y']]

        for c in new_colors:
            self.__agr.set_color(c[1], c[2], idx=c[0])

        self.__agr.write(outfile)


class PDFPrintExporter:
    def __init__(self, graphview):
        self.graphic = graphview

    def export(self, outfile):
        printer = QtPrintSupport.QPrinter()

        printer.setOutputFormat(printer.PdfFormat)
        printer.setOutputFileName(outfile)

        printer.setPaperSize(QtCore.QSizeF(self.graphic.width(), self.graphic.height()),
                             printer.DevicePixel)
        printer.setPageMargins(0, 0, 0, 0, printer.DevicePixel)

        painter = QtGui.QPainter(printer)
        self.graphic.render(painter)
        painter.end()
