from flask_restful import Resource
from werkzeug.utils import secure_filename
import globals
import os
from src import auth
from fontTools import ttLib
from contextlib import redirect_stderr
from webargs.flaskparser import use_kwargs, parser, abort
from webargs import fields
from bson import json_util, ObjectId
import json

fontsDB = globals.fontsDB

auth_args = {"Authorization": fields.Str(required=True)}


def font_name(font_path):

    font = ttLib.TTFont(font_path, ignoreDecompileErrors=True)
    with redirect_stderr(None):
        names = font['name'].names

    details = {}
    for x in names:
        if x.langID == 0 or x.langID == 1033:
            try:
                details[x.nameID] = x.toUnicode()
            except UnicodeDecodeError:
                details[x.nameID] = x.string.decode(errors='ignore')

    return details[4]


# class Uploads
class FontUpload(Resource):

    # files_args = {"fonts": fields.List(fields.Field(validate=lambda file: file.filename.split(".")[-1].lower() in ["ttf", "otf", "woff", "woff2", "eot", "fnt"]), required=True)}
    files_args = {"fonts": fields.Field(validate=lambda file: file.filename.split(".")[-1].lower() in ["ttf", "otf", "woff", "woff2", "eot", "fnt"], required=True)}
    fontName = {"fontname": fields.Str(required=True)}

    @use_kwargs(files_args, location="files")
    @use_kwargs(auth_args, location="headers")
    @use_kwargs(fontName, location="form")
    def post(self, Authorization, fonts,fontname):
        if auth.verify(str(Authorization).split(" ")[1]):
            savefonts = []
            filename = secure_filename(fonts.filename)
            tmpFilepath = os.path.join(globals.FONT_FOLDER, "tmp", filename)
            if not os.path.exists(tmpFilepath):
                fonts.save(tmpFilepath)
                fontName = font_name(tmpFilepath)
                existing = fontsDB.find_one({"name": fontName})
                if not existing:
                    filepath = os.path.join(globals.FONT_FOLDER, filename)
                    os.rename(tmpFilepath, filepath)
                    if fontname:
                        inserted_id = str(fontsDB.insert_one({"name": fontName, "path": filepath, "alias": [fontName,fontname]}).inserted_id)
                        return {"id": inserted_id, "name": fontName, "path": filepath}, 200
                    else:
                        inserted_id = str(fontsDB.insert_one({"name": fontName, "path": filepath, "alias": [fontName]}).inserted_id)
                        return {"id": inserted_id, "name": fontName, "path": filepath}, 200
                else:
                    return {"msg": "Files Already Exist"}, 201
            else:
                return {"msg": "Files Already Exist"}, 201
        else:
            return "Unauthorized! Access Denied", 401


class GetFont(Resource):
    search_arg = {"searchPhase": fields.Str(required=True)}

    @use_kwargs(auth_args, location="headers")
    @use_kwargs(search_arg, location="query")
    def get(self, Authorization, searchPhase):
        if auth.verify(str(Authorization).split(" ")[1]):
            fonts = list(fontsDB.find({"$or": [
                {'name': {'$regex': searchPhase, "$options": 'i'}},
                {'alias': {'$regex': searchPhase, "$options": 'i'}}
            ]}))
            return json.loads(json_util.dumps(fonts)), 200
        else:
            return "Unauthorized! Access Denied", 401

class deleteFont(Resource):
    search_arg = {"id": fields.Str(required=True)}

    @use_kwargs(auth_args, location="headers")
    @use_kwargs(search_arg, location="query")
    def delete(self,Authorization,id):
        if auth.verify(str(Authorization).split(" ")[1]):
            fonts = fontsDB.delete_one({"_id": ObjectId(id)})
            return json.loads(json_util.dumps(fonts)), 200
        else:
            return "Unauthorized! Access Denied", 401

# This error handler is necessary for usage with Flask-RESTful
@parser.error_handler
def handle_request_parsing_error(err, req, schema, *, error_status_code, error_headers):
    """webargs error handler that uses Flask-RESTful's abort function to return
    a JSON error response to the client.
    """
    if not error_status_code:
        abort(400, errors=err.messages)
    else:
        abort(error_status_code, errors=err.messages)
