import numpy as np
import pytest

from pandas import (
    DataFrame,
    Series,
)
import pandas._testing as tm


class TestDataFramePctChange:
    @pytest.mark.parametrize(
        "periods, exp",
        [
            (1, [np.nan, np.nan, np.nan, 1, 1, 1.5, np.nan, np.nan]),
            (-1, [np.nan, np.nan, -0.5, -0.5, -0.6, np.nan, np.nan, np.nan]),
        ],
    )
    def test_pct_change_with_nas(self, periods, exp, frame_or_series):
        vals = [np.nan, np.nan, 1, 2, 4, 10, np.nan, np.nan]
        obj = frame_or_series(vals)

        res = obj.pct_change(periods=periods)
        tm.assert_equal(res, frame_or_series(exp))

    def test_pct_change_numeric(self):
        # GH#11150
        pnl = DataFrame(
            [np.arange(0, 40, 10), np.arange(0, 40, 10), np.arange(0, 40, 10)]
        ).astype(np.float64)
        pnl.iat[1, 0] = np.nan
        pnl.iat[1, 1] = np.nan
        pnl.iat[2, 3] = 60

        for axis in range(2):
            expected = pnl / pnl.shift(axis=axis) - 1
            result = pnl.pct_change(axis=axis)
            tm.assert_frame_equal(result, expected)

    def test_pct_change(self, datetime_frame):
        rs = datetime_frame.pct_change()
        tm.assert_frame_equal(rs, datetime_frame / datetime_frame.shift(1) - 1)

        rs = datetime_frame.pct_change(2)
        filled = datetime_frame.ffill()
        tm.assert_frame_equal(rs, filled / filled.shift(2) - 1)

        rs = datetime_frame.pct_change()
        tm.assert_frame_equal(rs, datetime_frame / datetime_frame.shift(1) - 1)

        rs = datetime_frame.pct_change(freq="5D")
        tm.assert_frame_equal(
            rs,
            (datetime_frame / datetime_frame.shift(freq="5D") - 1).reindex_like(
                datetime_frame
            ),
        )

    def test_pct_change_shift_over_nas(self):
        s = Series([1.0, 1.5, np.nan, 2.5, 3.0])

        df = DataFrame({"a": s, "b": s})

        chg = df.pct_change()
        expected = Series([np.nan, 0.5, np.nan, np.nan, 0.2])
        edf = DataFrame({"a": expected, "b": expected})
        tm.assert_frame_equal(chg, edf)

    @pytest.mark.parametrize(
        "freq, periods",
        [
            ("5B", 5),
            ("3B", 3),
            ("14B", 14),
        ],
    )
    def test_pct_change_periods_freq(
        self,
        datetime_frame,
        freq,
        periods,
    ):
        # GH#7292
        rs_freq = datetime_frame.pct_change(freq=freq)
        rs_periods = datetime_frame.pct_change(periods)
        tm.assert_frame_equal(rs_freq, rs_periods)

        empty_ts = DataFrame(index=datetime_frame.index, columns=datetime_frame.columns)
        rs_freq = empty_ts.pct_change(freq=freq)
        rs_periods = empty_ts.pct_change(periods)
        tm.assert_frame_equal(rs_freq, rs_periods)


def test_pct_change_with_duplicated_indices():
    # GH30463
    data = DataFrame(
        {0: [np.nan, 1, 2, 3, 9, 18], 1: [0, 1, np.nan, 3, 9, 18]}, index=["a", "b"] * 3
    )

    result = data.pct_change()

    second_column = [np.nan, np.inf, np.nan, np.nan, 2.0, 1.0]
    expected = DataFrame(
        {0: [np.nan, np.nan, 1.0, 0.5, 2.0, 1.0], 1: second_column},
        index=["a", "b"] * 3,
    )
    tm.assert_frame_equal(result, expected)


def test_pct_change_none_beginning():
    # GH#54481
    df = DataFrame(
        [
            [1, None],
            [2, 1],
            [3, 2],
            [4, 3],
            [5, 4],
        ]
    )
    result = df.pct_change()
    expected = DataFrame(
        {0: [np.nan, 1, 0.5, 1 / 3, 0.25], 1: [np.nan, np.nan, 1, 0.5, 1 / 3]}
    )
    tm.assert_frame_equal(result, expected)
