# -*- coding: utf-8 -*-
# :Project:   SoL -- save_changes() tests
# :Created:   sab 07 lug 2018 07:31:07 CEST
# :Author:    Lele Gaifax <lele@metapensiero.it>
# :License:   GNU General Public License version 3 or later
# :Copyright: © 2018 Lele Gaifax
#

from os.path import exists, join
from tempfile import gettempdir

import pytest

from sol.models import Competitor, Player, Tourney, User
from sol.models.bio import save_changes
from sol.models.errors import OperationAborted


def test_insert_user(session):
    # email is missing
    with pytest.raises(OperationAborted) as e:
        save_changes(session, None, [
            ('iduser', dict(firstname='New',
                            lastname='user',
                            password='test')),
        ], [])
    assert 'are mandatory' in str(e)

    with pytest.raises(OperationAborted) as e:
        save_changes(session, None, [
            ('iduser', dict(firstname='New',
                            lastname='user',
                            password='test',
                            email='')),
        ], [])
    assert 'are mandatory' in str(e)

    # weak password
    with pytest.raises(OperationAborted) as e:
        save_changes(session, None, [
            ('iduser', dict(firstname='New',
                            lastname='user',
                            email='user@example.com',
                            password='test')),
        ], [])
    assert 'Password' in str(e) and 'weak' in str(e)

    with pytest.raises(OperationAborted) as e:
        save_changes(session, None, [
            ('iduser', dict(firstname='New',
                            lastname='User',
                            email='admin',
                            password='tst123')),
        ], [])
    assert 'is reserved' in str(e)

    i, m, d = save_changes(session, None, [
        ('iduser', dict(firstname='New ',
                        lastname='user ',
                        email='user@example.com ',
                        password='tst123')),
    ], [])
    assert len(i) == 1
    assert len(m) == 0
    assert len(d) == 0

    new = session.query(User).get(i[0]['iduser'])
    assert new.firstname == 'New'
    assert new.lastname == 'User'
    assert new.email == 'user@example.com'
    assert new.password and new.password != 'tst123'

    # Dup email
    with pytest.raises(OperationAborted) as e:
        save_changes(session, None, [
            ('iduser', dict(firstname='New',
                            lastname='Again',
                            email='user@example.com',
                            password='test123')),
        ], [])
    assert 'already exists' in str(e)


def test_modify_user(session):
    with pytest.raises(OperationAborted) as e:
        save_changes(session, None, [
            ('iduser', dict(iduser=1,
                            lastname='')),
        ], [])
    assert 'cannot be empty' in str(e)

    with pytest.raises(OperationAborted) as e:
        save_changes(session, None, [
            ('iduser', dict(iduser=1,
                            firstname='')),
        ], [])
    assert 'cannot be empty' in str(e)

    with pytest.raises(OperationAborted) as e:
        save_changes(session, None, [
            ('iduser', dict(iduser=1,
                            email='')),
        ], [])
    assert 'provide a valid "email"' in str(e)

    with pytest.raises(OperationAborted) as e:
        save_changes(session, None, [
            ('iduser', dict(iduser=1,
                            password='test')),
        ], [])
    assert 'Password is too weak' in str(e)

    with pytest.raises(OperationAborted) as e:
        save_changes(session, None, [
            ('iduser', dict(iduser=1,
                            email='admin')),
        ], [])
    assert 'is reserved' in str(e)

    i, m, d = save_changes(session, None, [
        ('iduser', dict(iduser=1,
                        email='user@example.com ',
                        password='tst123')),
    ], [])
    assert len(i) == 0
    assert len(m) == 1
    assert len(d) == 0

    session.expunge_all()
    chg = session.query(User).get(1)
    assert chg.password is not None and chg.password != 'test'
    assert chg.email == 'user@example.com'


def test_bad_player_name(session):
    with pytest.raises(OperationAborted) as e:
        save_changes(session, None, [
            ('idplayer', dict(firstname='New',
                              lastname=' ')),
        ], [])
    assert 'lastname' in str(e) and 'mandatory' in str(e)

    with pytest.raises(OperationAborted) as e:
        save_changes(session, None, [
            ('idplayer', dict(firstname=' ',
                              lastname=' ')),
        ], [])
    assert 'lastname' in str(e) and 'mandatory' in str(e)

    with pytest.raises(OperationAborted) as e:
        save_changes(session, None, [
            ('idplayer', dict(idplayer=1,
                              firstname=' ')),
        ], [])
    assert 'cannot be empty' in str(e)

    with pytest.raises(OperationAborted) as e:
        save_changes(session, None, [
            ('idplayer', dict(idplayer=1,
                              lastname=' ')),
        ], [])
    assert 'cannot be empty' in str(e)


def test_bad_description(session, fake_admin_request):
    for key in ('idchampionship', 'idclub', 'idrating', 'idtourney'):
        with pytest.raises(OperationAborted) as e:
            save_changes(session, None, [(key, {'description': ' '})], [])
        assert 'description' in str(e) and 'mandatory' in str(e)
        session.rollback()

        with pytest.raises(OperationAborted) as e:
            save_changes(session, fake_admin_request,
                         [(key, {key: 1, 'description': ' '})], [])
        assert 'description' in str(e) and 'cannot be empty' in str(e)

    for key in ('idchampionship', 'idclub', 'idrating', 'idtourney'):
        with pytest.raises(OperationAborted) as e:
            save_changes(session, None, [(key, {'guid': 'bar'})], [])
        assert 'description' in str(e) and 'mandatory' in str(e)
        session.rollback()


def test_delete(session):
    # player is playing!
    with pytest.raises(OperationAborted) as e:
        save_changes(session, None, [], [('idplayer', 1)])
    assert 'not allowed' in str(e) and 'is a competitor' in str(e)

    i, m, d = save_changes(session, None, [
        ('idplayer', dict(firstname='New',
                          lastname='user',
                          nickname='test',
                          email='user@example.com',
                          password='tst123')),
    ], [])
    assert len(i) == 1
    assert len(m) == 0
    assert len(d) == 0

    tbdid = i[0]['idplayer']
    i, m, d = save_changes(session, None, [], [('idplayer', tbdid)])
    session.flush()
    assert len(i) == 0
    assert len(m) == 0
    assert len(d) == 1

    session.expunge_all()
    deleted = session.query(Player).get(tbdid)
    assert deleted is None

    # user owns something!
    with pytest.raises(OperationAborted) as e:
        save_changes(session, None, [], [('iduser', 1)])
    assert 'not allowed' in str(e) and 'owns' in str(e)


def test_upload_portrait(session):
    basedir = gettempdir()

    img = ("data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA"
           "AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO"
           "9TXL0Y4OHwAAAABJRU5ErkJggg==")

    i, m, d = save_changes(session, None, [
        ('idplayer', dict(idplayer=1, image=img, portrait='bar.jpeg')),
    ], [])
    assert len(i) == 0
    assert len(m) == 1
    assert len(d) == 0

    assert exists(join(basedir, 'b60ab2708daec7685f3d412a5e05191a.jpeg'))

    i, m, d = save_changes(session, None, [
        ('idplayer', dict(idplayer=1, portrait=None)),
    ], [])
    assert len(i) == 0
    assert len(m) == 1
    assert len(d) == 0

    assert not exists(join(basedir, 'b60ab2708daec7685f3d412a5e05191a.jpeg'))


def test_upload_emblem(session):
    basedir = gettempdir()

    img = ("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA"
           "AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO"
           "9TXL0Y4OHwAAAABJRU5ErkJggg==")

    i, m, d = save_changes(session, None, [
        ('idclub', dict(idclub=1, image=img, emblem='foo.png')),
    ], [])
    assert len(i) == 0
    assert len(m) == 1
    assert len(d) == 0

    assert exists(join(basedir, 'b60ab2708daec7685f3d412a5e05191a.png'))

    i, m, d = save_changes(session, None, [
        ('idclub', dict(idclub=1, emblem=None)),
    ], [])
    assert len(i) == 0
    assert len(m) == 1
    assert len(d) == 0

    assert not exists(join(basedir, 'b60ab2708daec7685f3d412a5e05191a.png'))


def test_insert_and_modify(session, tourney_double, player_lele, player_bob, player_fata):
    tid = tourney_double.idtourney
    lid = player_lele.idplayer
    bid = player_bob.idplayer
    fid = player_fata.idplayer

    leleteam = session.query(Competitor).filter_by(idtourney=tid, idplayer1=lid).one()

    i, m, d = save_changes(session, None, [
        ('idcompetitor', dict(idcompetitor=0,
                              idtourney=tid,
                              idplayer1=bid,
                              idplayer2=fid)),
        ('idcompetitor', dict(idcompetitor=leleteam.idcompetitor,
                              idplayer2=None))
        ], [])
    assert len(i) == 1
    assert len(m) == 1
    assert len(d) == 0

    session.expunge_all()

    t = session.query(Tourney).get(tid)
    competitors = t.competitors
    assert len(competitors) == 3

    for c in competitors:
        if c.player1.idplayer == lid:
            assert c.idplayer2 is None
        elif c.player1.idplayer == bid:
            assert c.player2.idplayer == fid
