# -*- coding: utf-8 -*-

import numpy as np
import pytest

import pandas as pd
from pandas.core.arrays import TimedeltaArray
import pandas.util.testing as tm


class TestTimedeltaArrayConstructor(object):
    def test_only_1dim_accepted(self):
        # GH#25282
        arr = np.array([0, 1, 2, 3], dtype='m8[h]').astype('m8[ns]')

        with pytest.raises(ValueError, match="Only 1-dimensional"):
            # 2-dim
            TimedeltaArray(arr.reshape(2, 2))

        with pytest.raises(ValueError, match="Only 1-dimensional"):
            # 0-dim
            TimedeltaArray(arr[[0]].squeeze())

    def test_freq_validation(self):
        # ensure that the public constructor cannot create an invalid instance
        arr = np.array([0, 0, 1], dtype=np.int64) * 3600 * 10**9

        msg = ("Inferred frequency None from passed values does not "
               "conform to passed frequency D")
        with pytest.raises(ValueError, match=msg):
            TimedeltaArray(arr.view('timedelta64[ns]'), freq="D")

    def test_non_array_raises(self):
        with pytest.raises(ValueError, match='list'):
            TimedeltaArray([1, 2, 3])

    def test_other_type_raises(self):
        with pytest.raises(ValueError,
                           match="dtype bool cannot be converted"):
            TimedeltaArray(np.array([1, 2, 3], dtype='bool'))

    def test_incorrect_dtype_raises(self):
        # TODO: why TypeError for 'category' but ValueError for i8?
        with pytest.raises(ValueError,
                           match=r'category cannot be converted '
                                 r'to timedelta64\[ns\]'):
            TimedeltaArray(np.array([1, 2, 3], dtype='i8'), dtype='category')

        with pytest.raises(ValueError,
                           match=r"dtype int64 cannot be converted "
                                 r"to timedelta64\[ns\]"):
            TimedeltaArray(np.array([1, 2, 3], dtype='i8'),
                           dtype=np.dtype("int64"))

    def test_copy(self):
        data = np.array([1, 2, 3], dtype='m8[ns]')
        arr = TimedeltaArray(data, copy=False)
        assert arr._data is data

        arr = TimedeltaArray(data, copy=True)
        assert arr._data is not data
        assert arr._data.base is not data


class TestTimedeltaArray(object):
    def test_np_sum(self):
        # GH#25282
        vals = np.arange(5, dtype=np.int64).view('m8[h]').astype('m8[ns]')
        arr = TimedeltaArray(vals)
        result = np.sum(arr)
        assert result == vals.sum()

        result = np.sum(pd.TimedeltaIndex(arr))
        assert result == vals.sum()

    def test_from_sequence_dtype(self):
        msg = "dtype .*object.* cannot be converted to timedelta64"
        with pytest.raises(ValueError, match=msg):
            TimedeltaArray._from_sequence([], dtype=object)

    def test_abs(self):
        vals = np.array([-3600 * 10**9, 'NaT', 7200 * 10**9], dtype='m8[ns]')
        arr = TimedeltaArray(vals)

        evals = np.array([3600 * 10**9, 'NaT', 7200 * 10**9], dtype='m8[ns]')
        expected = TimedeltaArray(evals)

        result = abs(arr)
        tm.assert_timedelta_array_equal(result, expected)

    def test_neg(self):
        vals = np.array([-3600 * 10**9, 'NaT', 7200 * 10**9], dtype='m8[ns]')
        arr = TimedeltaArray(vals)

        evals = np.array([3600 * 10**9, 'NaT', -7200 * 10**9], dtype='m8[ns]')
        expected = TimedeltaArray(evals)

        result = -arr
        tm.assert_timedelta_array_equal(result, expected)

    def test_neg_freq(self):
        tdi = pd.timedelta_range('2 Days', periods=4, freq='H')
        arr = TimedeltaArray(tdi, freq=tdi.freq)

        expected = TimedeltaArray(-tdi._data, freq=-tdi.freq)

        result = -arr
        tm.assert_timedelta_array_equal(result, expected)

    @pytest.mark.parametrize("dtype", [
        int, np.int32, np.int64, 'uint32', 'uint64',
    ])
    def test_astype_int(self, dtype):
        arr = TimedeltaArray._from_sequence([pd.Timedelta('1H'),
                                             pd.Timedelta('2H')])
        result = arr.astype(dtype)

        if np.dtype(dtype).kind == 'u':
            expected_dtype = np.dtype('uint64')
        else:
            expected_dtype = np.dtype('int64')
        expected = arr.astype(expected_dtype)

        assert result.dtype == expected_dtype
        tm.assert_numpy_array_equal(result, expected)

    def test_setitem_clears_freq(self):
        a = TimedeltaArray(pd.timedelta_range('1H', periods=2, freq='H'))
        a[0] = pd.Timedelta("1H")
        assert a.freq is None


class TestReductions(object):

    def test_min_max(self):
        arr = TimedeltaArray._from_sequence([
            '3H', '3H', 'NaT', '2H', '5H', '4H',
        ])

        result = arr.min()
        expected = pd.Timedelta('2H')
        assert result == expected

        result = arr.max()
        expected = pd.Timedelta('5H')
        assert result == expected

        result = arr.min(skipna=False)
        assert result is pd.NaT

        result = arr.max(skipna=False)
        assert result is pd.NaT

    @pytest.mark.parametrize('skipna', [True, False])
    def test_min_max_empty(self, skipna):
        arr = TimedeltaArray._from_sequence([])
        result = arr.min(skipna=skipna)
        assert result is pd.NaT

        result = arr.max(skipna=skipna)
        assert result is pd.NaT
