# authentic2 - versatile identity manager
# Copyright (C) 2010-2021 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import datetime

from django.utils.timezone import now

from authentic2.a2_rbac.utils import get_default_ou
from authentic2_idp_oidc.models import OIDCAccessToken, OIDCAuthorization, OIDCClient, OIDCCode


def test_expired_manager(db, simple_user):
    expired = now() - datetime.timedelta(seconds=1)
    not_expired = now() + datetime.timedelta(days=1)
    client = OIDCClient.objects.create(
        name='client', slug='client', ou=get_default_ou(), redirect_uris='https://example.com/'
    )
    OIDCAuthorization.objects.create(client=client, user=simple_user, scopes='openid', expired=expired)
    OIDCAuthorization.objects.create(client=client, user=simple_user, scopes='openid', expired=not_expired)
    assert OIDCAuthorization.objects.count() == 2
    OIDCAuthorization.objects.cleanup()
    assert OIDCAuthorization.objects.count() == 1

    OIDCCode.objects.create(
        client=client,
        user=simple_user,
        scopes='openid',
        redirect_uri='https://example.com/',
        session_key='xxx',
        auth_time=now(),
        expired=expired,
    )
    OIDCCode.objects.create(
        client=client,
        user=simple_user,
        scopes='openid',
        redirect_uri='https://example.com/',
        session_key='xxx',
        auth_time=now(),
        expired=not_expired,
    )
    assert OIDCCode.objects.count() == 2
    OIDCCode.objects.cleanup()
    assert OIDCCode.objects.count() == 1

    OIDCAccessToken.objects.create(
        client=client, user=simple_user, scopes='openid', session_key='xxx', expired=expired
    )
    OIDCAccessToken.objects.create(
        client=client, user=simple_user, scopes='openid', session_key='xxx', expired=not_expired
    )
    assert OIDCAccessToken.objects.count() == 2
    OIDCAccessToken.objects.cleanup()
    assert OIDCAccessToken.objects.count() == 1


def test_access_token_is_valid_session(simple_oidc_client, simple_user, session):
    token = OIDCAccessToken.objects.create(
        client=simple_oidc_client, user=simple_user, scopes='openid', session_key=session.session_key
    )

    assert token.is_valid()
    session.flush()
    assert not token.is_valid()


def test_access_token_is_valid_expired(simple_oidc_client, simple_user, freezer):
    start = now()
    expired = start + datetime.timedelta(seconds=30)

    token = OIDCAccessToken.objects.create(
        client=simple_oidc_client, user=simple_user, scopes='openid', expired=expired
    )

    assert token.is_valid()
    freezer.move_to(expired)
    assert token.is_valid()
    freezer.move_to(expired + datetime.timedelta(seconds=1))
    assert not token.is_valid()


def test_access_token_is_valid_session_and_expired(simple_oidc_client, simple_user, session, freezer):
    start = now()
    expired = start + datetime.timedelta(seconds=30)

    token = OIDCAccessToken.objects.create(
        client=simple_oidc_client,
        user=simple_user,
        scopes='openid',
        session_key=session.session_key,
        expired=expired,
    )

    assert token.is_valid()
    freezer.move_to(expired)
    assert token.is_valid()
    freezer.move_to(expired + datetime.timedelta(seconds=1))
    assert not token.is_valid()
    freezer.move_to(start)
    assert token.is_valid()
    session.flush()
    assert not token.is_valid()
