#!/usr/bin/env python
# -*- coding: utf_8 -*-

import os
import sys
import copy
import time
import types
import json
import logging
import traceback
import re
import tempfile
import shutil
import base64
import uuid
from hashlib import md5 as fmd5
from urllib import parse
from datetime import datetime
from threading import Thread
from werkzeug.security import check_password_hash
from flask import request
from app.setting import config
from utils import md5_salt, random_string

logger = logging.getLogger("UploadManager")

FileStoragePath = os.getcwd()

# 判断目录是否存在,不存在则创建
# if not os.path.exists(os.path.join(FileStoragePath, config.get("UPLOAD_DIR"))):
#     os.makedirs(os.path.join(FileStoragePath, config.get("UPLOAD_DIR")))

def ajaxCheckAccess(path):
    realpath = os.path.realpath(path)
    if not realpath.startswith(FileStoragePath):
        return False
    return True

def checkPath(path):
    if not path:
        return False, {"code": -1, "data": None, "message": "[%s] arg missed!" % path}

    fpath = os.path.abspath(os.sep.join(
        [os.path.abspath(FileStoragePath), path]))

    if not ajaxCheckAccess(fpath):
        return False, {"code": -1, "data": None, "message": "You have no access to [%s]!" % fpath}

    if not os.path.exists(fpath):
        return False, {"code": -1, "data": None, "message": "[%s] is not existed!" % fpath}

    return True, os.path.abspath(fpath)

def saveToFile(saveFile, content):
    try:
        tfn = tempfile.mktemp()
        tf = open(tfn, 'w+b')
        tf.write(content)
        tf.close()
        os.rename(tfn, saveFile)
        return True
    except Exception as e:
        traceback.print_exc()
        logger.error(str(e))
        return False

def getFileInfo(infofile):
    info = dict()
    info.update({
        "isfile": os.path.isfile(infofile),
        "isdir": os.path.isdir(infofile),
        "size": os.path.getsize(infofile),
        "atime": os.path.getatime(infofile),
        "mtime": os.path.getmtime(infofile),
        "ctime": os.path.getctime(infofile),
        "name": os.path.basename(infofile)
    })
    return info

class UploadManager(object):
    def __init__(self):
        super(UploadManager, self).__init__()

    def download(self, data):
        obj = json.loads(data)
        isAccessed, path = checkPath(obj["path"])
        if not isAccessed:
            return {"code": -1, "data": None, "message": "invaild access"}

        if not os.path.isfile(path):
            return {"code": -1, "data": None, "message": "Path [%s] is not a valid file!" % path}

        try:
            with open(path, "rb") as f:
                content = base64.b64encode(f.read())
            md5code = fmd5(content).hexdigest()

            return {
                "data": {
                    "content": content,
                    "md5": md5code,
                    "filename": os.path.basename(path)
                },
                "code": 0,
                "message": "download file [%s] successfully!" % obj['path']
            }
        except Exception as e:
            traceback.print_exc()
            logger.error(str(e))
            return {
                "data": None,
                "code": -1,
                "message": "upload file [%s] failed!\n %s" % (obj['path'], repr(e))
            }

    def upload(self):
        try:
            binfile = request.files.get("binfile")
            if not binfile:
                return None, "file can not be null"

            obj = dict()
            obj['filename'] = binfile.filename
            obj['content'] = binfile.stream.read()

            # 目录结构:模块类型/年/月/项目名/文件名_时间日期.文件后缀
            # 模块类型:项目管理模块、资质管理模块、
            # filename = random_string() + os.path.splitext(obj['filename'])[-1]
            current = datetime.now() # 文件重命名后缀
            # 拼接文件名
            filename = os.path.splitext(obj['filename'])[0] + "_{}".format(current.strftime("%Y%m%d%H%M%S")) + os.path.splitext(obj['filename'])[-1]
            # 获取相对路径
            relative_path = os.path.join(config.get("UPLOAD_DIR"))
            # 获取最终存储的绝对路径
            savePath = os.path.normpath(os.sep.join([config.get("UPLOAD_PATH"), relative_path]))
            # 获取最终存储的文件路径
            saveFile = os.path.normpath(os.sep.join([savePath, filename]))

            if not os.path.exists(savePath):
                os.makedirs(savePath)

            with open(saveFile, 'wb') as f: # 保存文件
                f.write(obj['content'])

            return {
                "uuid": str(uuid.uuid4()), # 附件唯一编号
                "filename": obj['filename'], # 附件名称
                "filesize": os.path.getsize(saveFile), # 附件大小
                "filepath": os.sep.join([relative_path, filename]).replace("\\", "/"), # 附件存储路径
            }, "upload file [%s] successfully!" % obj['filename']
        except Exception as e:  # repr(e)
            traceback.print_exc()
            logger.error(str(e))
            return None, repr(e)

    def delete(self, data):
        try:
            isAccessed, path = checkPath(data["path"])
            if not isAccessed:
                return {"code": -1, "data": None, "message": "invaild access"}

            if os.path.isfile(path):
                os.remove(path)
                return {"code": 0, "data": None, "message": "delete file [%s] successfully!" % path}
            elif os.path.isdir(path):
                os.rmdir(path)
                return {"code": 0, "data": None, "message": "delete dir [%s] successfully!" % path}
            else:
                return {"code": 0, "data": None, "message": "Path [%s] is not a valid file or path!" % path}
        except Exception as e:
            traceback.print_exc()
            logger.error(str(e))
            return {"code": -1, "data": None, "message": repr(e)}

    def dirlist(self, data):
        obj = json.loads(data)
        isAccessed, path = checkPath(obj["path"])
        if not isAccessed:
            return {"code": -1, "data": None, "message": "invaild access"}

        result = []
        for p in os.listdir(path):
            result.append(getFileInfo(os.path.join(FileStoragePath, p)))
        return {"code": 0, "result": result, "message": "Get [%s] successfully!" % path}

    def filemd5(self, data):
        obj = json.loads(data)
        isAccessed, path = checkPath(obj["path"])
        if not isAccessed:
            return {"code": -1, "data": None, "message": "invaild access"}

        if not os.path.isfile(path):
            return {"code": -1, "data": None, "message": "Path [%s] is not a valid file!" % path}

        with open(path, "rb") as f:
            filemd5 = fmd5(f.read()).hexdigest()
        return {"code": 0, "result": filemd5, "message": "Get md5 of [%s] successfully!" % path}

    def fileinfo(self, data):
        obj = json.loads(data)
        isAccessed, path = checkPath(obj["path"])
        if not isAccessed:
            return {"code": -1, "data": None, "message": "invaild access"}

        if not os.path.isfile(path):
            return {"code": -1, "data": None, "message": "Path [%s] is not a valid file!" % path}

        return {"code": 0, "result": getFileInfo(path), "message": "Get md5 of [%s] successfully!" % path}


uploadManager = UploadManager()