import datetime
import os

from PyPDF2 import PdfFileMerger
from django.contrib.auth.decorators import login_required, permission_required
from django.http import Http404, FileResponse
from django.shortcuts import render, redirect
from django.utils import timezone

from schoolapps.settings import SHORT_WEEK_DAYS, LONG_WEEK_DAYS
from timetable.pdf import generate_class_tex, generate_pdf

from untisconnect.plan import get_plan, TYPE_TEACHER, TYPE_CLASS, TYPE_ROOM, parse_lesson_times
from untisconnect.sub import get_substitutions_by_date, generate_sub_table, get_header_information
from untisconnect.api import *
from userinformation import UserInformation

from schoolapps.settings import BASE_DIR


def get_all_context():
    teachers = get_all_teachers()
    classes = get_all_classes()
    rooms = get_all_rooms()
    subjects = get_all_subjects()
    context = {
        'teachers': teachers,
        'classes': classes,
        'rooms': rooms,
        'subjects': subjects
    }
    return context


@login_required
@permission_required("timetable.show_plan")
def all(request):
    context = get_all_context()
    return render(request, 'timetable/all.html', context)


@login_required
@permission_required("timetable.show_plan")
def quicklaunch(request):
    context = get_all_context()
    return render(request, 'timetable/quicklaunch.html', context)


def get_calendar_weeks(year=timezone.datetime.now().year):
    weeks = []

    # Get first day of year > first calendar week
    first_day_of_year = timezone.datetime(year=year, month=1, day=1)
    if first_day_of_year.isoweekday() != 1:
        days_to_next_monday = 1 - first_day_of_year.isoweekday()
        first_day_of_year += datetime.timedelta(days=days_to_next_monday)

    # Go for all weeks in year and create week dict
    first_day_of_week = first_day_of_year
    for i in range(52):
        calendar_week = i + 1
        last_day_of_week = first_day_of_week + datetime.timedelta(days=4)
        weeks.append({
            "calendar_week": calendar_week,
            "first_day": first_day_of_week,
            "last_day": last_day_of_week
        })
        first_day_of_week += datetime.timedelta(weeks=1)

    return weeks


def get_calendar_week(calendar_week, year=timezone.datetime.now().year):
    weeks = get_calendar_weeks(year=year)
    for week in weeks:
        if week["calendar_week"] == calendar_week:
            return week
    return None


@login_required
@permission_required("timetable.show_plan")
def plan(request, plan_type, plan_id, regular="", year=timezone.datetime.now().year,
         calendar_week=timezone.datetime.now().isocalendar()[1]):
    if regular == "regular":
        smart = False
    else:
        smart = True

    monday_of_week = get_calendar_week(calendar_week, year)["first_day"]
    # print(monday_of_week)

    if plan_type == 'teacher':
        _type = TYPE_TEACHER
        el = get_teacher_by_id(plan_id)
    elif plan_type == 'class':
        _type = TYPE_CLASS
        el = get_class_by_id(plan_id)
    elif plan_type == 'room':
        _type = TYPE_ROOM
        el = get_room_by_id(plan_id)
    else:
        raise Http404('Plan not found.')

    plan, holidays = get_plan(_type, plan_id, smart=smart, monday_of_week=monday_of_week)
    # print(parse_lesson_times())

    context = {
        "smart": smart,
        "type": _type,
        "raw_type": plan_type,
        "id": plan_id,
        "plan": plan,
        "el": el,
        "times": parse_lesson_times(),
        "weeks": get_calendar_weeks(year=year),
        "selected_week": calendar_week,
        "selected_year": year,
        "short_week_days": zip(SHORT_WEEK_DAYS, holidays),
        "long_week_days": zip(LONG_WEEK_DAYS, holidays),
        "holidays": holidays,
    }

    return render(request, 'timetable/plan.html', context)


@login_required
@permission_required("timetable.show_plan")
def my_plan(request, year=None, day=None, month=None):
    date = timezone.datetime.now()
    if year is not None and day is not None and month is not None:
        date = timezone.datetime(year=year, month=month, day=day)

    # Get next weekday if it is a weekend
    next_weekday = get_next_weekday(date)
    if next_weekday != date:
        return redirect("timetable_my_plan", next_weekday.year, next_weekday.month, next_weekday.day)

    calendar_week = date.isocalendar()[1]
    monday_of_week = get_calendar_week(calendar_week, date.year)["first_day"]

    _type = UserInformation.user_type(request.user)

    if _type == UserInformation.TEACHER:
        _type = TYPE_TEACHER
        shortcode = request.user.username
        el = get_teacher_by_shortcode(shortcode)
        plan_id = el.id
        raw_type = "teacher"
        # print(el)
    elif _type == UserInformation.STUDENT:
        _type = TYPE_CLASS
        _name = UserInformation.user_classes(request.user)[0]
        # print(_name)
        el = get_class_by_name(_name)
        plan_id = el.id
        raw_type = "class"
    else:
        return redirect("timetable_admin_all")
    # print(monday_of_week)

    plan, holidays = get_plan(_type, plan_id, smart=True, monday_of_week=monday_of_week)
    # print(parse_lesson_times())

    holiday_for_the_day = holidays[date.isoweekday() - 1]
    # print(holiday_for_the_day)

    context = {
        "type": _type,
        "raw_type": raw_type,
        "id": plan_id,
        "plan": plan,
        "el": el,
        "times": parse_lesson_times(),
        "week_day": date.isoweekday() - 1,
        "date": date,
        "date_js": int(date.timestamp()) * 1000,
        "display_date_only": True,
        "holiday": holiday_for_the_day,
    }
    # print(context["week_day"])

    return render(request, 'timetable/myplan.html', context)


def get_next_weekday(date):
    """Get the next weekday by a datetime object"""

    if date.isoweekday() in {6, 7}:
        if date.isoweekday() == 6:
            plus = 2
        else:
            plus = 1
        date += datetime.timedelta(days=plus)
    return date


def sub_pdf(request):
    """Show substitutions as PDF for the next weekday (specially for monitors)"""

    # Get the next weekday
    today = timezone.datetime.now()

    first_day = get_next_weekday(today)
    second_day = get_next_weekday(today + datetime.timedelta(days=1))

    # Get subs and generate table
    for i, date in enumerate([first_day, second_day]):
        # Get subs and generate table
        subs = get_substitutions_by_date(date)
        sub_table = generate_sub_table(subs)
        header_info = get_header_information(subs, date)
        
        # Generate LaTeX
        tex = generate_class_tex(sub_table, date, header_info)

        # Generate PDF
        generate_pdf(tex, "class{}".format(i))

    # Merge PDFs
    merger = PdfFileMerger()
    class0 = open(os.path.join(BASE_DIR, "latex", "class0.pdf"), "rb")
    class1 = open(os.path.join(BASE_DIR, "latex", "class1.pdf"), "rb")
    merger.append(fileobj=class0)
    merger.append(fileobj=class1)

    # Write merged PDF to class.pdf
    output = open(os.path.join(BASE_DIR, "latex", "class.pdf"), "wb")
    merger.write(output)
    output.close()

    # Read and response PDF
    file = open(os.path.join(BASE_DIR, "latex", "class.pdf"), "rb")
    return FileResponse(file, content_type="application/pdf")


@login_required
@permission_required("timetable.show_plan")
def substitutions(request, year=None, day=None, month=None):
    """Show substitutions in a classic view"""

    date = timezone.datetime.now()
    if year is not None and day is not None and month is not None:
        date = timezone.datetime(year=year, month=month, day=day)

    # Get subs and generate table
    subs = get_substitutions_by_date(date)
    sub_table = generate_sub_table(subs)

    context = {
        "subs": subs,
        "sub_table": sub_table,
        "date": date,
        "date_js": int(date.timestamp()) * 1000
    }

    return render(request, 'timetable/substitution.html', context)