#! /usr/bin/env python
# -*- coding: UTF-8 -*-
#

from __future__ import absolute_import, unicode_literals, division

from datetime import date

from flask import (
    Blueprint, render_template, url_for, request, redirect, flash, abort
)
from flask_login import current_user, login_required, fresh_login_required

from oclubs.objs import Activity, User, Club, Upload, FormattedText
from oclubs.enums import UserType, ClubType, ClubJoinMode, ActivityTime
from oclubs.shared import (
    download_xlsx, get_callsign_decorator, special_access_required,
    render_email_template, Pagination, require_active_club,
    require_student_membership, require_membership, require_not_student,
    true_or_fail, form_is_valid, fail
)
from oclubs.exceptions import UploadNotSupported, AlreadyExists, NoRow
from oclubs.access import siteconfig

clubblueprint = Blueprint('clubblueprint', __name__)


@clubblueprint.route('/view/<clubfilter:club_filter>')
def clublist(club_filter):
    '''Club list by club type'''
    num = 20
    clubs = Club.randomclubs(num, **club_filter.to_kwargs())
    info = {}
    for club in clubs:
        info[club.name] = club.activities()[0] \
            if club.activities() else None

    return render_template('club/clublist.html.j2',
                           is_list=True,
                           clubs=clubs,
                           info=info,
                           club_filter=club_filter)


@clubblueprint.route('/')
def home_redirect():
    return redirect(url_for('.clublist', club_filter='all'))


@clubblueprint.route('/<club>/')
@get_callsign_decorator(Club, 'club')
def clubintro(club):
    '''Club Intro'''
    free_join = (current_user.is_authenticated and
                 (club.joinmode == ClubJoinMode.FREE_JOIN and
                  current_user.type == UserType.STUDENT and
                  current_user not in club.members))
    see_email = (current_user.is_authenticated and
                 (current_user.type == UserType.ADMIN or
                  current_user == club.leader))
    is_admin = (current_user.is_authenticated and
                (current_user.type == UserType.CLASSROOM_ADMIN or
                 current_user.type == UserType.DIRECTOR or
                 current_user.type == UserType.ADMIN))

    invite_member = club.joinmode == ClubJoinMode.BY_INVITATION

    return render_template('club/clubintro.html.j2',
                           free_join=free_join,
                           see_email=see_email,
                           is_admin=is_admin,
                           invite_member=invite_member)


@clubblueprint.route('/<club>/introduction/submit', methods=['POST'])
@get_callsign_decorator(Club, 'club')
@login_required
@require_active_club
def clubintro_submit(club):
    '''Add new member'''
    true_or_fail(current_user.type == UserType.STUDENT,
                 'You may not join clubs.', 'join')
    true_or_fail(club.joinmode == ClubJoinMode.FREE_JOIN,
                 'You may not join this club.', 'join')
    if form_is_valid():
        try:
            club.add_member(current_user)
        except AlreadyExists:
            fail('You are already in %s.' % club.name, 'join')
            return redirect(url_for('.clubintro', club=club.callsign))
        parameters = {'club': club, 'current_user': current_user}
        contents = render_email_template('joinclubs', parameters)
        club.leader.email_user('New Club Member - ' + club.name, contents)
        club.leader.notify_user('%s has joined %s.'
                                % (current_user.nickname, club.name))
        flash('You have successfully joined ' + club.name + '.', 'join')
    return redirect(url_for('.clubintro', club=club.callsign))


@clubblueprint.route('/<club>/new_leader')
@get_callsign_decorator(Club, 'club')
@require_active_club
@special_access_required
@fresh_login_required
def newleader(club):
    '''Selecting New Club Leader'''
    return render_template('club/newleader.html.j2')


@clubblueprint.route('/<club>/new_leader/submit', methods=['POST'])
@get_callsign_decorator(Club, 'club')
@require_active_club
@special_access_required
@fresh_login_required
def newleader_submit(club):
    '''Change leader in database'''
    leader_old = club.leader
    members_obj = club.members
    leader_name = request.form['leader']

    for member_obj in members_obj:
        if leader_name == member_obj.passportname:
            club.leader = member_obj
            break
    else:
        abort(500)
    for member in club.teacher_and_members:
        parameters = {'user': member, 'club': club, 'leader_old': leader_old}
        contents = render_email_template('newleader', parameters)
        member.email_user('New Leader - ' + club.name, contents)
        member.notify_user(club.leader.nickname +
                           ' becomes the new leader of ' + club.name + '.')
    return redirect(url_for('.clubintro', club=club.callsign))


@clubblueprint.route('/<club>/members')
@get_callsign_decorator(Club, 'club')
@require_membership
def memberinfo(club):
    '''Check Members' Info'''
    has_access = (current_user == club.leader or
                  current_user == club.teacher or
                  current_user.type == UserType.ADMIN)
    return render_template('club/memberinfo.html.j2',
                           has_access=has_access)


@clubblueprint.route('/<club>/members/notify_members', methods=['POST'])
@get_callsign_decorator(Club, 'club')
@require_active_club
@special_access_required
def memberinfo_notify_members(club):
    '''Allow club leader to notify members'''
    notify_contents = request.form['contents']
    if not notify_contents:
        flash('Contents cannot be blank', 'notify_members')
        return redirect(url_for('.memberinfo', club=club.callsign))
    for member in club.members:
        member.notify_user(notify_contents)
        parameters = {'member': member,
                      'club': club,
                      'notify_contents': notify_contents}
        contents = render_email_template('notifymembers', parameters)
        member.email_user('Notification - ' + club.name, contents)
    flash('Notification sent.', 'notify_members')
    return redirect(url_for('.memberinfo', club=club.callsign))


@clubblueprint.route('/<club>/members/download')
@get_callsign_decorator(Club, 'club')
@require_membership
@special_access_required
def memberinfo_download(club):
    '''Download members' info'''
    info = []
    info.append(('Nick Name', 'Class', 'Passport Name', 'Email'))
    info.extend([(member.nickname, member.grade_and_class, member.passportname,
                  member.email) for member in club.members])
    return download_xlsx('Member Info.xlsx', info)


@clubblueprint.route('/<club>/edit_info')
@get_callsign_decorator(Club, 'club')
@require_active_club
@special_access_required
def changeclubinfo(club):
    '''Change Club's Info'''
    return render_template('club/changeclubinfo.html.j2')


@clubblueprint.route('/<club>/edit_info/submit', methods=['GET', 'POST'])
@get_callsign_decorator(Club, 'club')
@require_active_club
@special_access_required
def changeclubinfo_submit(club):
    '''Change club's info'''
    intro = request.form['intro']
    if len(intro) > 90:
        fail('Your one sentence description is too long.', 'clubinfo')
        return redirect(url_for('.changeclubinfo', club=club.callsign))
    elif request.form['intro'] != '':
        club.intro = request.form['intro']

    desc = request.form['description'].strip()

    if desc:
        club.description = FormattedText.handle(current_user, club,
                                                request.form['description'])

    if 'picture' in request.files:
        file = request.files['picture']
        if file.filename != '':
            try:
                club.picture = Upload.handle(current_user, club,
                                             file)
            except UploadNotSupported:
                fail('Please upload the correct file type.', 'clubinfo')
                return redirect(url_for('.changeclubinfo', club=club.callsign))

    teacher_email = request.form['email']

    if teacher_email != club.teacher.studentid:
        club.teacher = User.find_teacher(teacher_email)
    location = request.form['location']
    if location != club.location and location != '':
        club.location = location
    for member in club.teacher_and_members:
        parameters = {'user': member, 'club': club}
        contents = render_email_template('changeclubinfo', parameters)
        member.email_user('Change Club Info - ' + club.name, contents)
        member.notify_user(club.name + '\'s information has been changed.')
    return redirect(url_for('.clubintro', club=club.callsign))


@clubblueprint.route('/<club>/adjust_member')
@get_callsign_decorator(Club, 'club')
@require_active_club
@special_access_required
@fresh_login_required
def adjustmember(club):
    '''Adjust Club Members'''
    invite_member = club.joinmode == ClubJoinMode.BY_INVITATION
    return render_template('club/adjustmember.html.j2',
                           invite_member=invite_member)


@clubblueprint.route('/<club>/adjust_member/submit', methods=['POST'])
@get_callsign_decorator(Club, 'club')
@require_active_club
@special_access_required
@fresh_login_required
def adjustmember_submit(club):
    '''Input adjustment of club members'''
    member = User(request.form['uid'])
    true_or_fail(current_user != member,
                 'You cannot expel yourself.', 'expelled')
    if form_is_valid():
        club.remove_member(member)
        parameters = {'member': member, 'club': club}
        contents = render_email_template('adjustmember', parameters)
        member.email_user('Member Adjustment - ' + club.name, contents)
        member.notify_user('You have been moved out of ' + club.name + '.')
        flash(member.nickname + ' has been expelled.', 'expelled')
    return redirect(url_for('.adjustmember', club=club.callsign))


@clubblueprint.route('/<club>/invite_member/submit', methods=['POST'])
@get_callsign_decorator(Club, 'club')
@require_active_club
@special_access_required
@fresh_login_required
def invitemember(club):
    '''Allow club leader to invite member'''
    true_or_fail(club.joinmode == ClubJoinMode.BY_INVITATION,
                 'You cannot invite members when the join mode is not '
                 'by invitation.', 'invite_member')
    if form_is_valid():
        new_member = User.find_user(request.form['gradeclass'],
                                    request.form['gnumber'])
        if new_member is None: