"""This is the main flask distribusi page"""
import os
import zipfile
import shutil
from datetime import timedelta


from flask import (
    render_template,
    redirect,
    url_for,
    session,
    send_from_directory,
)
from flask_login import (
    logout_user,
    login_required,
    current_user,
)

from flask_wtf.csrf import CSRFError

from app import create_app, db, login_manager
from usermodel import User
from distribusimodel import Distribusis

# Forms!
from forms.uploadform import UploadForm
from forms.distribusiform import DistribusiForm
from forms.themeform import ThemeForm
from forms.editorform import EditorForm
from forms.selectorform import SelectorForm

# CRUD!
from selector import SelectNewDistribusi
from selector import SelectUpdateDistribusi
from selector import DeleteDistribusi
from selector import SelectorVisible

# Upload
from upload import UploadNewDistribusi
from upload import UploadUpdatedFiles

# UserPengguna
from statuspengguna.helper import IsZipUploaded
from statuspengguna.helper import IsCssSelected
from statuspengguna.helper import CurrentDistribusi
from statuspengguna.helper import ResetUserState
from statuspengguna.loginuser import LoginUser
from statuspengguna.registeruser import RegisterUser

# Tada!
from distribusi.cli import build_argparser
from distribusi.distribusi import distribusify

APP = create_app()


@APP.before_request
def session_handler():
    session.permanent = True
    APP.permanent_session_lifetime = timedelta(minutes=30)


@APP.route("/")
def index():
    ResetUserState()
    uploadform = UploadForm()
    distribusis = Distribusis.query.filter(
        Distribusis.distribusiname.isnot(None)
    ).all()
    distribusies = {}
    for distribusi in distribusis:
        user = User.query.filter_by(id=distribusi.userid).first()
        #distribusies[distribusi.distribusiname] = user.email
        distribusies[user.email] = distribusi
        singledistribusi = {
            "name": distribusi.distribusiname,
            "term": distribusi.term,
            "course": distribusi.course,
            "year": distribusi.year,
            "tags": distribusi.tags.split(','),
        }
        distribusies[user.email] = singledistribusi
    years = uploadform.academicyear.choices
    terms = uploadform.term.choices
    courses = uploadform.course.choices
    print(type(courses[0]))
    template = render_template(
        "index.html",
        distribusies=distribusies,
        years=years,
        terms=terms,
        courses=courses,
    )
    return template


@APP.route("/distribusi", methods=["GET", "POST"])
@login_required
def distribusi():
    uploadform = UploadForm()
    distribusiform = DistribusiForm()
    themeform = ThemeForm()
    selectorform = SelectorForm()
    selectorform.distribusis.choices = distribusisfields()

    selectorvisible = SelectorVisible()
    current_distribusi = CurrentDistribusi()
    files_uploaded = IsZipUploaded(current_distribusi)
    css_selected = IsCssSelected(current_distribusi)
    user = User.query.filter_by(email=current_user.email).first()
    distribusi = Distribusis.query.filter_by(
        distribusiname=current_distribusi
    ).first()

    if distribusiform.validate_on_submit():
        zipfilename = "{}.zip".format(distribusi.distribusiname)
        userfolder = os.path.join("stash", distribusi.distribusiname)
        unzipfile = os.path.join(userfolder, zipfilename)

        if os.path.exists(unzipfile):
            with zipfile.ZipFile(unzipfile, "r") as zip_ref:
                # To do, replace extractall with inspection and extract
                zip_ref.extractall(userfolder)
        if os.path.exists(unzipfile):
            os.remove(os.path.join(userfolder, zipfilename))
        # To Do: Make sure nothing can be executed from the upload folder
        cssfile = ""
        for filename in os.listdir(userfolder):
            if filename.endswith(".css"):
                cssfile = os.path.join(userfolder, filename)

        parser = build_argparser()
        args = parser.parse_args(["-s", cssfile])
        distribusify(args, userfolder)
        distribusi.visible = True
        user.currentdistribusi = None
        db.session.commit()
        return redirect(url_for("index"))
    template = render_template(
        "distribusi.html",
        uploadform=uploadform,
        distribusiform=distribusiform,
        themeform=themeform,
        selectorform=selectorform,
        files_uploaded=files_uploaded,
        css_selected=css_selected,
        selectorvisible=selectorvisible,
    )
    return template


@APP.route("/upload", methods=["POST"])
@login_required
def upload():
    distribusiform = DistribusiForm()
    themeform = ThemeForm()
    selectorform = SelectorForm()
    selectorform.distribusis.choices = distribusisfields()

    selectorvisible = SelectorVisible()

    current_distribusi = CurrentDistribusi()
    if current_distribusi == "new":
        uploadform = UploadNewDistribusi(APP.config["UPLOAD_FOLDER"])
    else:
        uploadform = UploadUpdatedFiles(APP.config["UPLOAD_FOLDER"])
    files_uploaded = IsZipUploaded(uploadform.sitename.data)
    css_selected = IsCssSelected(current_distribusi)
    template = render_template(
        "distribusi.html",
        uploadform=uploadform,
        distribusiform=distribusiform,
        themeform=themeform,
        selectorform=selectorform,
        files_uploaded=files_uploaded,
        css_selected=css_selected,
        selectorvisible=selectorvisible,
    )
    return template


@APP.route("/theme", methods=["GET", "POST"])
@login_required
def theme():
    uploadform = UploadForm()
    distribusiform = DistribusiForm()
    themeform = ThemeForm()
    selectorform = SelectorForm()
    selectorform.distribusis.choices = distribusisfields()

    selectorvisible = SelectorVisible()
    current_distribusi = CurrentDistribusi()
    files_uploaded = IsZipUploaded(current_distribusi)
    css_selected = IsCssSelected(current_distribusi)
    if themeform.validate_on_submit():
        newuserfolder = os.path.join("stash", current_distribusi)
        copycssfile = os.path.join(
            "themes",
            "{}.css".format(themeform.theme.data),
        )
        shutil.copy(copycssfile, newuserfolder)
        css_selected = IsCssSelected(current_distribusi)

    template = render_template(
        "distribusi.html",
        uploadform=uploadform,
        distribusiform=distribusiform,
        themeform=themeform,
        selectorform=selectorform,
        files_uploaded=files_uploaded,
        css_selected=css_selected,
        selectorvisible=selectorvisible,
    )
    return template


@APP.route("/editor", methods=["GET", "POST"])
@login_required
def editor():
    editorform = EditorForm()
    current_distribusi = CurrentDistribusi()
    files_uploaded = IsZipUploaded(current_distribusi)
    cssplaceholder = "Try out your CSS here"
    with open('themes/editor/placeholder.css') as f:
        cssplaceholder = f.read()
    editorform.css.data = cssplaceholder

    htmlplaceholder = "Write some test HTML here"
    with open('themes/editor/placeholder.html') as f:
        htmlplaceholder = f.read()
    print(htmlplaceholder)
    if editorform.validate_on_submit():
        userfolder = os.path.join("stash", current_distribusi)
        cssfilename = "{}.css".format(editorform.cssname.data)
        with open(os.path.join(userfolder, cssfilename), "w") as cssfile:
            cssfile.write(editorform.css.data)
            cssfile.close

    template = render_template(
        "editor.html",
        files_uploaded=files_uploaded,
        editorform=editorform,
        htmlplaceholder=htmlplaceholder,
    )
    return template


@APP.route("/selector", methods=["GET", "POST"])
@login_required
def selector():
    selectorform = SelectorForm()
    uploadform = UploadForm()
    distribusiform = DistribusiForm()
    themeform = ThemeForm()
    selectorform = SelectorForm()
    selectorform.distribusis.choices = distribusisfields()
    current_distribusi = CurrentDistribusi()
    if selectorform.validate_on_submit():
        if selectorform.new.data:
            selectorform = SelectNewDistribusi()
        if selectorform.delete.data:
            selectorform = DeleteDistribusi(selectorform.distribusis.data)
            selectorform.distribusis.choices = distribusisfields()
        if selectorform.update.data:
            selectorform = SelectUpdateDistribusi(
                selectorform.distribusis.data
            )
            current_distribusi = CurrentDistribusi()
            distribusi = Distribusis.query.filter_by(
                distribusiname=current_distribusi
            ).first()
            uploadform.sitename.data = distribusi.distribusiname
            uploadform.sitename.render_kw = {"readonly": True}
            uploadform.term.data = distribusi.term
            uploadform.course.data = distribusi.course
            uploadform.academicyear.data = distribusi.year
            uploadform.tags.data = distribusi.tags

    files_uploaded = IsZipUploaded(current_distribusi)
    css_selected = IsCssSelected(current_distribusi)
    selectorvisible = SelectorVisible()

    template = render_template(
        "distribusi.html",
        uploadform=uploadform,
        distribusiform=distribusiform,
        themeform=themeform,
        selectorform=selectorform,
        files_uploaded=files_uploaded,
        css_selected=css_selected,
        selectorvisible=selectorvisible,
    )
    return template


@APP.route("/stash/<path:path>")
def distribusistash(path):
    return send_from_directory("stash", path)


@APP.route("/admin")
@login_required
def admin():
    return "admin"


@APP.route("/logout")
@login_required
def logout():
    logout_user()
    return redirect(url_for("index"))


@APP.route("/login", methods=["GET", "POST"])
def login():
    result = LoginUser()
    return result


@APP.route("/register", methods=["GET", "POST"])
def register():
    result = RegisterUser()
    return result


@APP.errorhandler(CSRFError)
def handle_csrf_error(e):
    return render_template("csrf_error.html", reason=e.description), 400


@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))


def distribusisfields():
    distribusinames = []
    user = User.query.filter_by(email=current_user.email).first()
    for distribusi in Distribusis.query.filter_by(userid=user.id).all():
        distribusinames.append(distribusi.distribusiname)
    return distribusinames


if __name__ == "__main__":
    APP.debug = True
    APP.run(port=5000)