import pytz
from flask import render_template, url_for, redirect, abort, request, session
from flask_login import current_user
from notifications_utils.clients import DeskproError

from app import convert_to_boolean, current_service, service_api_client, deskpro_client
from app.main import main
from app.main.forms import SupportType, Feedback, Problem, Triage
from datetime import datetime


QUESTION_TICKET_TYPE = 'ask-question-give-feedback'
PROBLEM_TICKET_TYPE = "report-problem"


@main.route('/feedback', methods=['GET'])
def old_feedback():
    return redirect(url_for('.support'))


@main.route('/support', methods=['GET', 'POST'])
def support():
    form = SupportType()
    if form.validate_on_submit():
        return redirect(url_for(
            '.feedback',
            ticket_type=form.support_type.data,
        ))
    return render_template('views/support/index.html', form=form)


@main.route('/support/triage', methods=['GET', 'POST'])
def triage():
    form = Triage()
    if form.validate_on_submit():
        return redirect(url_for(
            '.feedback',
            ticket_type=PROBLEM_TICKET_TYPE,
            severe=form.severe.data
        ))
    return render_template(
        'views/support/triage.html',
        form=form
    )


@main.route('/support/submit/<ticket_type>')
def old_submit_feedback(ticket_type):
    try:
        ticket_type = {
            'problem': PROBLEM_TICKET_TYPE,
            'question': QUESTION_TICKET_TYPE,
        }[ticket_type]
        return redirect(url_for(
            '.feedback',
            ticket_type=ticket_type,
        ), 301)
    except KeyError:
        abort(404)


@main.route('/support/<ticket_type>', methods=['GET', 'POST'])
def feedback(ticket_type):
    try:
        form = {
            QUESTION_TICKET_TYPE: Feedback,
            PROBLEM_TICKET_TYPE: Problem,
        }[ticket_type]()
    except KeyError:
        abort(404)

    if not form.feedback.data:
        form.feedback.data = session.pop('feedback_message', '')

    if request.args.get('severe') in ['yes', 'no']:
        severe = convert_to_boolean(request.args.get('severe'))
    else:
        severe = None

    urgent = (
        in_business_hours() or
        (ticket_type == PROBLEM_TICKET_TYPE and severe)
    )

    anonymous = (
        (not form.email_address.data) and
        (not current_user.is_authenticated)
    )

    if needs_triage(ticket_type, severe):
        session['feedback_message'] = form.feedback.data
        return redirect(url_for('.triage'))

    if needs_escalation(ticket_type, severe):
        return redirect(url_for('.bat_phone'))

    if current_user.is_authenticated:
        form.email_address.data = current_user.email_address
        form.name.data = current_user.name

    if form.validate_on_submit():
        user_email = form.email_address.data
        user_name = form.name.data or None
        if current_service:
            service_string = 'Service "{name}": {url}\n'.format(
                name=current_service['name'],
                url=url_for('main.service_dashboard', service_id=current_service['id'], _external=True)
            )
        else:
            service_string = ''

        feedback_msg = 'Environment: {}\n{}{}\n{}'.format(
            url_for('main.index', _external=True),
            service_string,
            '' if user_email else '{} (no email address supplied)'.format(form.name.data),
            form.feedback.data
        )

        try:
            deskpro_client.create_ticket(
                subject='Notify feedback {}'.format(user_name),
                message=feedback_msg,
                ticket_type=ticket_type,
                urgency=10 if urgent else 1,
                user_email=user_email,
                user_name=user_name
            )
        except DeskproError:
            abort(500, "Feedback submission failed")
        return redirect(url_for('.thanks', urgent=urgent, anonymous=anonymous))

    return render_template(
        'views/support/{}.html'.format(ticket_type),
        form=form,
        ticket_type=ticket_type,
    )


@main.route('/support/escalate', methods=['GET', 'POST'])
def bat_phone():

    if current_user.is_authenticated:
        return redirect(url_for('main.feedback', ticket_type=PROBLEM_TICKET_TYPE))

    return render_template('views/support/bat-phone.html')


@main.route('/support/thanks', methods=['GET', 'POST'])
def thanks():
    return render_template(
        'views/support/thanks.html',
        urgent=convert_to_boolean(request.args.get('urgent')),
        anonymous=convert_to_boolean(request.args.get('anonymous')),
        logged_in=current_user.is_authenticated,
    )


def in_business_hours():

    now = datetime.utcnow().replace(tzinfo=pytz.utc)

    if is_weekend(now) or is_bank_holiday(now):
        return False

    return london_time_today_as_utc(9, 30) <= now < london_time_today_as_utc(17, 30)


def london_time_today_as_utc(hour, minute):
    return pytz.timezone('Europe/London').localize(
        datetime.now().replace(hour=hour, minute=minute)
    ).astimezone(pytz.utc)


def is_weekend(time):
    return time.strftime('%A') in {
        'Saturday',
        'Sunday',
    }


def is_bank_holiday(time):
    return time.strftime('%Y-%m-%d') in {
        # taken from https://www.gov.uk/bank-holidays.json
        "2016-01-01",
        "2016-03-25",
        "2016-03-28",
        "2016-05-02",
        "2016-05-30",
        "2016-08-29",
        "2016-12-26",
        "2016-12-27",
        "2017-01-02",
        "2017-04-14",
        "2017-04-17",
        "2017-05-01",
        "2017-05-29",
        "2017-08-28",
        "2017-12-25",
        "2017-12-26",
        "2018-01-01",
        "2018-03-30",
        "2018-04-02",
        "2018-05-07",
        "2018-05-28",
        "2018-08-27",
        "2018-12-25",
        "2018-12-26",
        "2019-01-01",
        "2019-04-19",
        "2019-04-22",
        "2019-05-06",
        "2019-05-27",
        "2019-08-26",
        "2019-12-25",
        "2019-12-26",
    }


def has_live_services(user_id):
    return any(
        service['restricted'] is False
        for service in service_api_client.get_services({'user_id': user_id})['data']
    )


def needs_triage(ticket_type, severe):
    return all((
        ticket_type == PROBLEM_TICKET_TYPE,
        severe is None,
        (
            not current_user.is_authenticated or has_live_services(current_user.id)
        ),
        not in_business_hours(),
    ))


def needs_escalation(ticket_type, severe):
    return all((
        ticket_type == PROBLEM_TICKET_TYPE,
        severe,
        not current_user.is_authenticated,
        not in_business_hours(),
    ))
