from datetime import (
    datetime,
    timedelta,
)
import re

import numpy as np
import pytest

from pandas._libs.tslibs import period as libperiod
from pandas.errors import InvalidIndexError

import pandas as pd
from pandas import (
    DatetimeIndex,
    NaT,
    Period,
    PeriodIndex,
    Series,
    Timedelta,
    date_range,
    notna,
    period_range,
)
import pandas._testing as tm
from pandas.core.api import (
    Float64Index,
    Int64Index,
)

dti4 = date_range("2016-01-01", periods=4)
dti = dti4[:-1]
rng = pd.Index(range(3))


@pytest.fixture(
    params=[
        dti,
        dti.tz_localize("UTC"),
        dti.to_period("W"),
        dti - dti[0],
        rng,
        pd.Index([1, 2, 3]),
        pd.Index([2.0, 3.0, 4.0]),
        pd.Index([4, 5, 6], dtype="u8"),
        pd.IntervalIndex.from_breaks(dti4),
    ]
)
def non_comparable_idx(request):
    # All have length 3
    return request.param


class TestGetItem:
    def test_getitem_slice_keeps_name(self):
        idx = period_range("20010101", periods=10, freq="D", name="bob")
        assert idx.name == idx[1:].name

    def test_getitem(self):
        idx1 = period_range("2011-01-01", "2011-01-31", freq="D", name="idx")

        for idx in [idx1]:
            result = idx[0]
            assert result == Period("2011-01-01", freq="D")

            result = idx[-1]
            assert result == Period("2011-01-31", freq="D")

            result = idx[0:5]
            expected = period_range("2011-01-01", "2011-01-05", freq="D", name="idx")
            tm.assert_index_equal(result, expected)
            assert result.freq == expected.freq
            assert result.freq == "D"

            result = idx[0:10:2]
            expected = PeriodIndex(
                ["2011-01-01", "2011-01-03", "2011-01-05", "2011-01-07", "2011-01-09"],
                freq="D",
                name="idx",
            )
            tm.assert_index_equal(result, expected)
            assert result.freq == expected.freq
            assert result.freq == "D"

            result = idx[-20:-5:3]
            expected = PeriodIndex(
                ["2011-01-12", "2011-01-15", "2011-01-18", "2011-01-21", "2011-01-24"],
                freq="D",
                name="idx",
            )
            tm.assert_index_equal(result, expected)
            assert result.freq == expected.freq
            assert result.
freq == "D"

            result = idx[4::-1]
            expected = PeriodIndex(
                ["2011-01-05", "2011-01-04", "2011-01-03", "2011-01-02", "2011-01-01"],
        
        freq="D",
                name="idx",
            )
            tm.assert_index_equal(result, expected)
            assert result.freq == expected.freq
            assert result.freq == "D"

    def test_getitem_index(self):
        idx = period_range("2007-01", periods=10, freq="M", name="x")

        result = idx[[1, 3, 5]]
        exp = PeriodIndex(["2007-02", "2007-04", "2007-06"], freq="M", name="x")
        tm.assert_index_equal(result, exp)

        result = idx[[True, True, False, False, False, True, True, False, False, False]]
        exp = PeriodIndex(
            ["2007-01", "2007-02", "2007-06", "2007-07"], freq="M", name="x"
        )
        tm.assert_index_equal(result, exp)

    def test_getitem_partial(self):
        rng = period_range("2007-01", periods=50, freq="M")
        ts = Series(np.random.randn(len(rng)), rng)

        with pytest.raises(KeyError, match=r"^'2006'$"):
            ts["2006"]

        result = ts["2008"]
        assert (result.index.year == 2008).all()

        result = ts["2008":"2009"]
        assert len(result) == 24

        result = ts["2008-1":"2009-12"]
        assert len(result) == 24

        result = ts["2008Q1":"2009Q4"]
        assert len(result) == 24

        result = ts[:"2009"]
        assert len(result) == 36

        result = ts["2009":]
        assert len(result) == 50 - 24

        exp = result
        result = ts[24:]
        tm.assert_series_equal(exp, result)

        ts = pd.concat([ts[10:], ts[10:]])
        msg = "left slice bound for non-unique label: '2008'"
        with pytest.raises(KeyError, match=msg):
            ts[slice("2008", "2009")]

    def test_getitem_datetime(self):
        rng = period_range(start="2012-01-01", periods=10, freq="W-MON")
        ts = Series(range(len(rng)), index=rng)

        dt1 = datetime(2011, 10, 2)
        dt4 = datetime(2012, 4, 20)

        rs = ts[dt1:dt4]
        tm.assert_series_equal(rs, ts)

    def test_getitem_nat(self):
        idx = PeriodIndex(["2011-01", "NaT", "2011-02"], freq="M")
        assert idx[0] == Period("2011-01", freq="M")
        assert idx[1] is NaT

        s = Series([0, 1, 2], index=idx)
        assert s[NaT] == 1

        s = Series(idx, index=idx)
        assert s[Period("2011-01", freq="M")] == Period("2011-01", freq="M")
        assert s[NaT] is NaT

    def test_getitem_list_periods(self):
        # GH 7710
        rng = period_range(start="2012-01-01", periods=10, freq="D")
        ts = Series(range(len(rng)), index=rng)
        exp = ts.iloc[[1]]
        tm.assert_series_equal(ts[[Period("2012-01-02", freq="D")]], exp)

    @pytest.mark.arm_slow
    def test_getitem_seconds(self):
        # GH#6716
        didx = date_range(start="2013/01/01 09:00:00", freq="S", periods=4000)
        pidx = period_range(start="2013/01/01 09:00:00", freq="S", periods=4000)

        for idx in [didx, pidx]:
            # getitem against index should raise ValueError
            values = [
                "2014",
                "2013/02",
                "2013/01/02",
                "2013/02/01 9H",
                "2013/02/01 09:00",
            ]
            for val in values:
                # GH7116
                # these show deprecations as we are trying
                # to slice with non-integer indexers
                with pytest.raises(IndexError, match="only integers, slices"):
                    idx[val]

            ser = Series(np.random.rand(len(idx)), index=idx)
            tm.assert_series_equal(ser["2013/01/01 10:00"], ser[3600:3660])
            tm.assert_series_equal(ser["2013/01/01 9H"], ser[:3600])
            for d in ["2013/01/01", "2013/01", "2013"]:
                tm.assert_series_equal(ser[d], ser)

    def test_getitem_day(self):
        # GH#6716
        # Confirm DatetimeIndex and PeriodIndex works identically
        didx = date_range(start="2013/01/01", freq="D", periods=400)
        pidx = period_range(start="2013/01/01", freq="D", periods=400)

        for idx in [didx, pidx]:
            # getitem against index should raise ValueError
            values = [
                "2014",
                "2013/02",
                "2013/01/02",
                "2013/02/01 9H",
                "2013/02/01 09:00",
            ]
            for val in values:

                # GH7116
                # these show deprecations as we are trying
                # to slice with non-integer indexers
                with pytest.raises(IndexError, match="only integers, slices"):
                    idx[val]

            ser = Series(np.random.rand(len(idx)), index=idx)
            tm.assert_series_equal(ser["2013/01"], ser[0:31])
            tm.assert_series_equal(ser["2013/02"], ser[31:59])
            tm.assert_series_equal(ser["2014"], ser[365:])

            invalid = ["2013/02/01 9H", "2013/02/01 09:00"]
            for val in invalid:
                with pytest.raises(KeyError, match=val):
                    ser[val]


class TestGetLoc:
    def test_get_loc_msg(self):
        idx = period_range("2000-1-1", freq="A", periods=10)
        bad_period = Period("2012", "A")
        with pytest.raises(KeyError, match=r"^Period\('2012', 'A-DEC'\)$"):
            idx.get_loc(bad_period)

        try:
            idx.get_loc(bad_period)
        except KeyError as inst:
            assert inst.args[0] == bad_period

    def test_get_loc_nat(self):
        didx = DatetimeIndex(["2011-01-01", "NaT", "2011-01-03"])
        pidx = PeriodIndex(["2011-01-01", "NaT", "2011-01-03"], freq="M")

        # check DatetimeIndex compat
        for idx in [didx, pidx]:
   