import numpy as np

from .points import Points


class Signal(Points):
    """
    Extension of :class:`Points` for complex y values.
    """

    def __init__(self, x, y, **kwargs):
        y = np.atleast_1d(y)
        if (y.ndim == 1) or y.shape[0] == 1:
            y = y.astype(complex)
        else:
            y = y[0, :] + 1j * y[1, :]

        super().__init__(x, y, **kwargs)

        if len(self._x) > 1:
            self.dx = kwargs.get('dx', abs(self._x[1] - self._x[0]))
        else:
            self.dx = 0
        self.meta.update({'phase': [], 'shift': 0})

    def __repr__(self):
        return 'Signal: ' + self.name

    def swap(self):
        """

        Swaps real and imaginary part of y

        """
        self._y.real, self._y.imag = self._y.imag, self._y.real

        return self

    def phase(self, method: str = 'manual', **kwargs):
        if method == 'manual':
            self.manual_phase(**kwargs)
        elif method == 'simple':
            self.simple_phase(**kwargs)
        else:
            raise KeyError(f'Not implemented method {method}')

        return self

    def manual_phase(self, ph0: float = 0., ph1: float = 0., pvt: float = 0):
        self._y *= np.exp(-1j * ph0 * np.pi / 180.)
        if ph1 != 0:
            x = (self._x - pvt) / max(self._x)
            self._y *= np.exp(-1j * x * ph1 * np.pi / 180.)
        self.meta['phase'].append((ph0, ph1, pvt))

        return self

    def autophase(self, pos: float = 0, avg: int = 0):
        pos = np.argmin(np.abs(pos-self.x))
        ph = np.mean(np.angle(self.y)[pos-avg:pos+avg+1])
        self._y *= np.exp(-1j*ph)

        self.meta['phase'].append((ph, 0, 0))

        return self

    def baseline_spline(self, line):
        self._y -= line

        return self

    def divide(self, part):
        if part:
            self.cut(0.01*self._x[0], self._x[int(self.length//2)+1])
        else:
            self.cut(self._x[int(self.length//2)], 10*self._x[-1])

        return self

    def toarray(self, err=False):
        if not err or np.all(self._y_err == 0.):
            return np.c_[self._x, self._y.real, self._y.imag]
        else:
            return np.c_[self._x, self._y.real, self._y.imag, self._y_err]

    def tohdf(self, hdffile):
        grp = hdffile
        try:
            grp2 = grp.create_group(self.name)
            is_empty = True
        except ValueError:
            is_empty = False
            grp2 = grp[self.name]
        grp2.attrs['damaris_type'] = 'Accumulation'
        grp2.attrs['TITLE'] = self.group + '/' + self.name
        if is_empty:
            grp2.create_dataset('accu_data', data=np.c_[self._y.real, self._y.imag],
                                compression='gzip')
            idx = grp2.create_dataset('indices', (1,), dtype=np.dtype([('dwelltime', 'f')]))
            idx['dwelltime'] = self.dx
        else:
            grp2['accu_data'][...] = np.c_[self._y.real, self._y.imag]
            grp2['indices']['dwelltime'] = self.dx
