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

import os
import re
import json
import shutil
from datetime import datetime
from sqlalchemy import func, distinct
from application.app import db
from models.package import PackageModel
from models.annex import AnnexModel
from models.user import UserModel
from models.app import AppModel
from application.config import config
from webcreator.utils.epk import EpkApp
from webcreator.log import logger
from webcreator.response import ResponseCode

class AppResource(object):
    def __init__(self):
        super().__init__()

    def get(self, uuid, params):
        # handle business
        filters = [AppModel.is_delete==False, AppModel.uuid==uuid]
        app = AppModel.query.filter(*filters).one_or_none()
        if not app:
            return None, ResponseCode.HTTP_NOT_FOUND

        user = UserModel.query.filter(UserModel.id==params.get('user')).one_or_none()
        if not user:
            return False, ResponseCode.USER_NOT_EXISTS

        # 根据app查询应用，获取应用有哪些文件
        # 按格式创建文件夹，将这些文件移动到这个文件夹
        # 将这些零散文件进行打包
        # 更新数据库对应文件的路径

        source_files = AnnexModel.query.filter(AnnexModel.app==app).all()
        if not source_files:
            return None, ResponseCode.HTTP_NOT_FOUND

        dtNowString = datetime.now().strftime("%Y%m%d%H%M%S")
        dirname = "{}-{}-{}-{}".format(app.app_name, app.app_version, app.category, dtNowString)
        upload_dir = os.sep.join([config.UPLOAD_ROOT_DIR, config.EPK_DIR])
        target_dir = os.sep.join([upload_dir, dirname])
        dest_dir = os.sep.join([target_dir, "src"])
        if not os.path.exists(dest_dir):
            os.makedirs(dest_dir)

        app_files = []
        for sf in source_files:
            target_file = sf.path
            if not os.path.exists(sf.path):
                target_file = os.sep.join([config.UPLOAD_ROOT_DIR, sf.path])

        filename = os.path.basename(target_file)
        name, suffix = os.path.splitext(filename)
        name = re.sub(r"_\d{14}$", "", name)
        dst_file = os.path.normpath(os.sep.join([dest_dir, name + suffix]))
        shutil.copy(os.path.normpath(target_file), dst_file)
        app_files.append([sf.id, dst_file])

        with open(os.sep.join([target_dir, "epk.json"]), "w") as f:
            json.dump(app.to_dict(exclude=["uuid", "create_at", "update_at", "delete_at"]), f)

        # 打包成EPK文件
        app_info = {}
        params = { 'appName': app.app_name, 'appDir': dest_dir, 'appVersion': app.app_version, 'output': target_dir }
        if user.role == "administrator" or user.role == "community":
            params['algorithm'] = "h"
        epk = EpkApp(**params)
        app_info = epk.pack()
        app_info['md5'] = str(app_info['md5'])

        # 更新数据库对应文件路径
        # 将文件拷贝过去后，需要重新更新数据库文件记录
        epk_path = os.sep.join([target_dir.replace(config.UPLOAD_ROOT_DIR, ""), "{}.epk".format(app.app_name)]).replace('\\', '/')

        package = PackageModel.query.filter(PackageModel.app==app).one_or_none()
        if package:
            package.app_path = epk_path
            package.app_info = app_info
            package.update_by = user.id
            package.update_at = datetime.now()
            db.session.commit()

        # 新增一条AppLogs
        package = PackageModel(app=app.app_name, app_version=app.app_version, file_path=epk_path, package_info=app_info, create_by=user, create_at=datetime.now())
        db.session.add(package)
        db.session.commit()

        return { 'app_name': app.app_name, 'app_path': epk_path }, ResponseCode.HTTP_NOT_FOUND

    def getList(self, params):
        # handle business
        logger.warn(params)
        filters = [AppModel.is_delete==False]
        result = AppModel.query.filter(*filters).order_by(AppModel.create_at).paginate(params.get('page', 1), params.get('pageSize', 10), error_out=False)

        if not result:
            return None, ResponseCode.HTTP_NOT_FOUND

        user = UserModel.query.filter(UserModel.id==params.get('user')).one_or_none()
        if not user:
            return False, ResponseCode.USER_NOT_EXISTS

        temp = {}
        if user.role == "administrator":
            temp.update({"is_delete": False})
        else:
            temp.update({ "create_by": user, "is_delete": False })

        if "scope_type" in params and params.get("scope_type") == "list":
            result = AppModel.query.filter_by(**temp).order_by(AppModel.create_at.desc())
            temp = []
            for item in result:
                temp.append(item.to_dict(only=["uuid", "app_name"]))
            return (temp, len(temp)), ResponseCode.HTTP_SUCCESS
        elif "scope_type" in params and params.get("scope_type") == "distinct":
            result = db.session.query(AppModel, func.count(distinct(AppModel.name))).all()
            temp = []
            for item in result:
                temp.append(item)
            return (temp, len(temp)), ResponseCode.HTTP_SUCCESS

        result = AppModel.query.filter_by(**temp).order_by(AppModel.sort).order_by(AppModel.create_at.desc()).paginate(params.get("pagenum", 1), params.get("pagesize", 10), error_out=False)

        if result.total and len(result.items):
            temp = []
            for item in result.items:
                t = dict()
                t.update(item.to_json())
                t.update({
                    "create_by": item.create_by.to_dict(only=["uuid", "username"]),
                    "update_by": item.update_by.to_dict(only=["uuid", "username"]),
                    "create_at": item.create_at.strftime("%Y-%m-%d %H:%M:%S") if item.create_at else None,
                    "update_at": item.update_at.strftime("%Y-%m-%d %H:%M:%S") if item.update_at else None,
                })
                temp.append(t)
            result = temp
        return result, ResponseCode.HTTP_SUCCESS

    def post(self, params, jwt={}):
        # handle business
        # 应用打包
        # 插入一条打包记录

        logger.info(jwt)

        user = UserModel.query.filter(UserModel.uuid==jwt.get('uuid')).one_or_none()
        if not user:
            return False, ResponseCode.USER_NOT_EXISTS

        # 判断下app是否存在
        # result = Apps.select(app_name=data.get("app_name"), is_delete=False).count()
        # if result < 1:
        #     return False, "app_name has been exists."

        params.update({
            'app_icon': params["app_icon"].replace(config.UPLOAD_ROOT_DIR, ""),
            'create_by': user.id,
            'create_at': datetime.now(),
            'update_by': user.id,
            'update_at': datetime.now(),
        })

        app_files = []
        epk_path = ""
        if params.get("fileList"):
            app_files = params.get("fileList")
            params.pop("fileList")
            epk_path = params.get("epk_path")
            params.pop("epk_path")

        app = AppModel(**params)
        db.session.add(app)
        db.session.commit()

        # 在EPK目录下生成JSON文件
        with open(os.sep.join([os.path.dirname(epk_path), "epk.json"]), "w") as f:
            json.dump(app.to_dict(), f)

        for a in app_files:
            res = AnnexModel(app=app, title=os.path.basename(a), path=a, size=os.path.getsize(a), create_by=user, create_at=datetime.now(), update_by=user, update_at=datetime.now())
            db.session.add(res)
            db.session.flush()
        db.session.commit()

        app_info = {}
        params = { 'appName': app.app_name, 'appDir': epk_path, 'appVersion': app.app_version, 'output': os.path.dirname(epk_path) }
        if user.role == "administrator" or user.role == "community":
            params['algorithm'] ="h"
        epk = EpkApp(**params)
        app_info = epk.pack()

        epk_filename = os.sep.join([os.path.dirname(epk_path).replace(config.UPLOAD_ROOT_DIR, ""), "{}.epk".format(app.app_name)]).replace('\\', '/')
        if app_info:
            app_info['md5'] = str(app_info['md5'])

        package = PackageModel(app=app, file_path=epk_filename, app_version=params.get("app_version"), package_info=app_info, source=1, create_by=user, create_at=datetime.now(), update_by=user, update_at=datetime.now())
        db.session.add(package)
        db.session.commit()

        return True, ResponseCode.HTTP_SUCCESS

        # result = AppModel.query.filter(AppModel.app_name == params.get('app_name')).first()
        # if result and result.is_delete:
        #     result.is_delete = False
        #     result.update_by = jwt.get("id", "")
        #     result.update_date = datetime.now()
        #     db.session.commit()
        #     return True, ResponseCode.HTTP_SUCCESS
        # elif result and result.is_delete == False:
        #     return False, ResponseCode.HTTP_INVAILD_REQUEST

        # result = AppModel(**params)
        # db.session.add(result)
        # db.session.commit()
        # return True, ResponseCode.HTTP_SUCCESS

    def put(self, uuid, params, jwt={}):
        user = UserModel.query.filter(UserModel.id==params.get('user')).one_or_none()
        if not user:
            return False, ResponseCode.USER_NOT_EXISTS

        # handle business
        app = AppModel.query.filter(AppModel.uuid==uuid).first()
        if not app:
            return None, ResponseCode.HTTP_NOT_FOUND

        if params:
            # 更新文件
            if params.get("app_files"):
                for a in params.get("app_files"):
                    res = AnnexModel(app=app, title=a.get("filename"), path=a.get("filepath"), size=a.get("filesize"), create_by=user, create_at=datetime.now(), update_by=user, update_at=datetime.now())
                    db.session.add(res)
                    db.session.flush()
                db.session.commit()
                params.pop("app_files")

            # 更新icon
            if params.get("app_icon"):
                condition = { 'update_by': user, 'update_at': datetime.now() }
                if params.get("app_icon").get("filename"):
                    condition.update({"title": params.get("app_icon").get("filename")})
                if params.get("app_icon").get("filepath"):
                    condition.update({"path": params.get("app_icon").get("filepath")})
                if params.get("app_icon").get("filesize"):
                    condition.update({"size": params.get("app_icon").get("filesize")})

                params.pop("app_icon")

            for key, value in params.items():
                if value != None:
                    setattr(app, key, value)
            app.update_by = jwt.get("id", "")
            app.update_date = datetime.now()
            db.session.commit()
            return True, ResponseCode.HTTP_SUCCESS
        else:
            return False, ResponseCode.HTTP_INVAILD_REQUEST

    def delete(self, uuid, jwt={}):
        # handle business
        result = AppModel.query.filter(AppModel.uuid==uuid).first()
        if not result:
            return False, ResponseCode.HTTP_NOT_FOUND

        result.update_by = jwt.get("id", "")
        result.update_date = datetime.now()
        result.is_delete = True
        db.session.delete(result)
        db.session.commit()
        return True, ResponseCode.HTTP_SUCCESS

appManager = AppResource()