#!/usr/bin/env python

import flask
import markdown
import pystache
import sys
import web

import model
import storage

web.template.ALLOWED_AST_NODES.append("Constant")

app = flask.Flask(__name__)


class Templates:
    """
    Local module to contain mustache templates
    """

    renderer = pystache.Renderer(
        missing_tags=pystache.common.MissingTags.strict, search_dirs="templates",
    )

    def load_template(name):
        with open(f"templates/{name}.mustache") as f:
            parsed = pystache.parse(f.read())
        return lambda stuff: Templates.renderer.render(parsed, stuff)

    main = load_template("main")
    design_page = load_template("design_page")
    design_list = load_template("design_list")
    text_list = load_template("text_list")

    edit_design_list = load_template("edit_design_list")
    edit_design = load_template("edit_design")
    delete_design = load_template("delete_design")

    photo_upload = load_template("photo_upload")
    photo_list = load_template("photo_list")
    photo_tile = load_template("photo_tile")
    photo_delete = load_template("photo_delete")
    view_photo = load_template("view_photo")

    edit_pages = load_template("edit_pages")
    edit_page = load_template("edit_page")


db = storage.DB()
PER_PAGE = 16


def main(func):
    def new_func(*args, **kwargs):
        title, content = func(*args, **kwargs)
        return Templates.main({"title": title, "content": content})

    new_func.__name__ = func.__name__
    return new_func


@app.route("/")
@main
def index():
    return "Frony Ritter Designs", model.Page.get(name="main").rendered()


@app.route("/design/<id>/<_slug>/")
@main
def get_design(id, _slug=None):
    design = model.Design.get(visible_id=id)
    return "Designs", Templates.design_page(design)


@app.route("/api/design/<int:id>/")
def api_get_design(id: int):
    return flask.jsonify(model.Design.get(visible_id=id).to_json())


# @app.route('/design/<id>/<slug>', method=['POST'])
# def POST(self, id, slug='electric-boogaloo'):
#     try:
#         id = int(id)
#     except:
#         raise web.redirect('/')
#     input = dict(web.input())
#     if ('title' in input and
#         'description' in input and
#         'category' in input and
#         'tags' in input):
#         db.put_design(id,
#                       input['title'],
#                       input['description'],
#                       input['category'])
#         db.process_tag_list(id, input['tags'])
#         if not slug:
#             slug = slugify(input['title'])
#     raise web.redirect('/edit/design/{0:05}/slug/'.format(id, slug))


@app.route("/design/")
@main
def get_all_designs():
    page = int(flask.request.args.get("page") or 0)
    data = model.Design.get_where(page=page)
    return "Designs", Templates.design_list(data)


@app.route("/category/")
@main
def get_all_categories():
    return "Category", Templates.text_list(model.Category.all())


@app.route("/category/<cat>/")
@main
def get_category(cat):
    page = int(flask.request.args.get("page") or 0)
    data = model.Design.get_where(category=cat, page=page)
    return cat.capitalize(), Templates.design_list(data)


@app.route("/category/<cat>/tag/<tag>/")
@main
def get_category_with_tag(cat, tag):
    page = int(flask.request.args.get("page") or 0)
    data = model.Design.get_where(tag=tag, category=cat, page=page)
    return cat.capitalize(), Templates.design_list(data)


@app.route("/tag/")
@main
def get_all_tags():
    return "All Tags", Templates.text_list(model.Tag.all())


@app.route("/tag/<tag>/")
@main
def get_tag(tag):
    page = int(flask.request.args.get("page") or 0)
    data = model.Design.get_where(tag=tag, page=page)
    pretty_tag = " ".join(w.capitalize() for w in tag.split("_"))
    return pretty_tag, Templates.design_list(data)


@app.route("/<name>/")
@main
def get_page(name):
    page = model.Page.get(name=name)
    return page.title, markdown.markdown(page.text)


@app.route("/edit/design/")
@main
def edit_all_designs():
    page = int(flask.request.args.get("page") or 0)
    data = model.Design.get_where(page=page)
    return "Edit Mode", Templates.edit_design_list(data)


@app.route("/edit/design/", methods=["POST"])
def post_new_design():
    id = model.Design.make_new()
    return flask.redirect(f"/edit/design/{id:05}/")


@app.route("/edit/design/<id>/")
@main
def edit_design(id):
    id = int(id)
    design = model.Design.get(visible_id=id)
    return (
        "design",
        Templates.edit_design(
            {
                "id": design.visible_id,
                "title": design.title,
                "tags": design.tags,
                "all_tags": model.Tag.select(model.Tag.tag_name)
                .distinct()
                .order_by(model.Tag.tag_name),
                "categories": design.category_list(),
                "description": design.description,
                "photos": design.photos,
                "id_str": f"{design.visible_id:05}",
            }
        ),
    )

@app.route("/edit/design/<id>/", methods=["POST"])
def update_design(id):
    id = int(id)
    model.Design.get(visible_id=id).update_with(flask.request.get_json())
    return flask.jsonify({"status": "ok"})


@app.route("/edit/delete/<id>/")
@main
def delete_design(id):
    id = int(id)
    design = model.Design.get(visible_id=id)
    return (
        "delete design",
        Templates.delete_design({"title": design.title, "id_str": f"{design.visible_id:05}",}),
    )


@app.route("/edit/delete/<id>/", methods=["POST"])
def do_delete_design(id):
    model.Design.get(visible_id=id).delete_instance()
    return flask.redirect(f"/edit/design/")


@app.route("/edit/photo/")
@main
def add_photo():
    if "id" in flask.request.args:
        id = flask.request.args.get("id")
        return f"Add photo for design {id}", Templates.photo_upload({"id": id})
    else:
        return "Add generic photo", Templates.photo_upload({"id": -1})


@app.route("/edit/photo/", methods=["POST"])
def do_add_photo():
    if "file" not in flask.request.files or "id" not in flask.request.form:
        return flask.redirect("/edit/photo")
    id = int(flask.request.form["id"])
    file = flask.request.files["file"]
    photo_id = model.Photo.upload(file, id)
    if id == -1:
        return flask.redirect(f"/edit/view-photo/{photo_id}")
    else:
        return flask.redirect(f"/edit/design/{id}")


@app.route("/edit/photo/<id>/")
@main
def modify_photo(id):
    design_id = flask.request.args.get('design_id', -1)
    return "Delete Photo", Templates.photo_delete({
        "id": id,
        "design_id": design_id
    })


@app.route("/edit/photo/<id>/", methods=["POST"])
def do_modify_photo(id):
    model.Photo.get(filename=id).delete_instance()
    if (d_id := int(flask.request.form.get('design_id', -1))) != -1:
        return flask.redirect(f"/edit/design/{d_id}/")
    else:
        return flask.redirect(f"/edit/design/")


@app.route("/edit/view-photo/")
@main
def view_all_photos():
    page = int(flask.request.args.get("page", 1))
    photos, p_min, p_max = model.Photo.get_all(page=page)
    return (
        "Photos",
        Templates.photo_list(
            {
                "photos": ({"photo": Templates.photo_tile(p)} for p in photos),
                "page": page,
                "prev_page": page - 1,
                "next_page": page + 1,
                "show_left": page > p_min,
                "show_right": page < p_max,
                "last_page": p_max,
            }
        ),
    )


@app.route("/edit/view-photo/<id>/")
@main
def view_photo(id):
    photo = model.Photo.get(filename=id)
    if photo:
        return f"Viewing photo {id}", Templates.view_photo(photo)
    else:
        raise Exception(f"Unable to find photo {id}")


@app.route("/edit/pages/")
@main
def edit_page_list():
    return "Edit Page List", Templates.edit_pages({"pages": model.Page.select()})


@app.route("/edit/pages/<slug>/")
@main
def edit_page(slug):
    page = model.Page.get(name=slug)
    return (
        f"Edit Page {slug}",
        Templates.edit_page({"name": slug, "title": page.title, "text": page.text,}),
    )


@app.route("/edit/pages/<slug>/", methods=["POST"])
def do_edit_page(slug):
    text = flask.request.form.get("text", "")
    title = flask.request.form.get("title", slug.capitalize())
    model.Page.update(title=title, text=text).where(model.Page.name == slug).execute()
    return flask.redirect(f"/edit/pages/{slug}")


if __name__ == "__main__":
    app.run()
