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

import os
import re
import json
import shutil
from pathlib import Path
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 import utils
from webcreator.utils.epk import EpkApp
from webcreator.log import logger
from webcreator.response import ResponseCode

@utils.ThreadMaker
def update_information(ip, record_id):
    try:
        jsonData = utils.get_location_by_ip(ip)
        if (0 != jsonData['status']):
            return None

        pack = PackageModel.query.filter(PackageModel.id==record_id).first()
        pack.geo_location = json.dumps(jsonData, ensure_ascii=False)
        pack.ip = ip
        db.session.commit()
    except Exception as e:
        logger.error(e)

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

    def get(self, uuid, jwt):
        # 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.uuid==jwt.get('uuid')).one_or_none()
        if not user:
            return False, ResponseCode.USER_NOT_EXISTS

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

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

        now_str = datetime.now().strftime("%Y%m%d%H%M%S")
        dirname = "{}-{}-{}-{}".format(app.app_name, app.app_version, app.category, now_str)
        target_dir = Path(config.UPLOAD_ROOT_DIR).joinpath(config.EPK_DIR).joinpath(dirname)
        dest_dir = target_dir.joinpath("src")
        if not dest_dir.exists():
            os.makedirs(dest_dir.resolve().as_posix())

        app_files = []
        for sf in source_files:
            target_file = Path(sf.path)
            if not target_file.exists():
                target_file = Path(config.UPLOAD_ROOT_DIR).joinpath(sf.path)
            
            name = re.sub(r"_\d{14}$", "", target_file.stem)
            suffix = target_file.suffix
            dst_file = dest_dir.joinpath(name + suffix)
            shutil.copy(target_file.resolve().as_posix(), dst_file.resolve().as_posix())
            app_files.append([sf.id, dst_file.resolve().as_posix()])

        target_dir.joinpath("epk.json").write_text(json.dumps(app.to_dict(), ensure_ascii=False), encoding="utf-8")

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

        # 更新数据库对应文件路径
        # 将文件拷贝过去后，需要重新更新数据库文件记录
        epk_path = target_dir.relative_to(config.UPLOAD_ROOT_DIR).joinpath("{}.epk".format(app.app_name)).resolve().as_posix()

        package = PackageModel.query.filter(PackageModel.app==app.id).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=json.dumps(app_info, ensure_ascii=False), create_by=user.id, create_at=datetime.now())
        db.session.add(package)
        app.update_by = user.id
        app.update_at = datetime.now()
        app.app_file_size = app_info.get("buff_length", 0)
        app.download_url = epk_path
        db.session.commit()

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

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

        temp = {}
        filters = [AppModel.is_delete==False]
        if user.role == 1:
            temp.update({ "is_delete": False })
        else:
            filters.append(AppModel.create_by==user.id)
            temp.update({ "create_by": user.id, "is_delete": False })
        logger.info(params)
        if "scope" in params and params.get("scope") == "list":
            result = AppModel.query.filter_by(**temp).order_by(AppModel.create_at.desc())
            temp = []
            for item in result:
                temp.append({
                    "uuid": item.uuid,
                    "app_name": item.app_name
                })
            return temp, ResponseCode.HTTP_SUCCESS
        elif "scope" in params and params.get("scope") == "distinct":
            result = db.session.query(AppModel, func.count(distinct(AppModel.name))).all()
            temp = []
            for item in result:
                temp.append(item)
            return temp, ResponseCode.HTTP_SUCCESS

        for p in params:
            if hasattr(AppModel, p) and params[p] != None:
                temp[p] = params[p]

        result = AppModel.query.filter_by(**temp).order_by(AppModel.create_at.desc()).paginate(params.get("page", 1), params.get("pageSize", 15), error_out=False)
        # result = AppModel.query.filter(*filters).order_by(AppModel.create_at.desc()).paginate(params.get('page', 1), params.get('pageSize', 15), error_out=False)

        if result.total and len(result.items):
            return result, ResponseCode.HTTP_SUCCESS

        return None, ResponseCode.HTTP_NOT_FOUND

    def post(self, params, jwt={}):
        # handle business
        # 应用打包
        # 插入一条打包记录
        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."
        algorithm = params.get('algorithm')
        if algorithm:
            params.pop("algorithm")
        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 = Path("")
        if params.get("fileList"):
            app_files = params.get("fileList")
            params.pop("fileList")
            epk_path = params.get("epk_path")
            params.pop("epk_path")
        if params.get("logo"):
            params.pop("logo")
        real_ip = params.get("real_ip", None)
        if real_ip:
            params.pop("real_ip")

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

        logger.info(params)

        # 在EPK目录下生成JSON文件
        epk_path.joinpath("epk.json").write_text(json.dumps(app.to_dict(), ensure_ascii=False), encoding="utf-8")
        # 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:
            t = Path(config.UPLOAD_ROOT_DIR).joinpath(a)
            res = AnnexModel(app=app.id, title=t.name, path=a, size=t.stat().st_size, create_by=user.id, create_at=datetime.now(), update_by=user.id, update_at=datetime.now())
            db.session.add(res)
            db.session.flush()
        db.session.commit()

        app_info = {}
        params = { 'appName': app.app_name, 'appDir': epk_path.resolve().as_posix(), 'appVersion': app.app_version, 'output': epk_path.parent.resolve().as_posix() }
        if user.role == 1:
            params['algorithm'] ="h"

        if algorithm:
            params['algorithm'] = algorithm

        epk = EpkApp(**params)
        app_info = epk.pack()

        epk_filename = epk_path.parent.relative_to(config.UPLOAD_ROOT_DIR).joinpath("{}.epk".format(app.app_name)).resolve().as_posix()
        if app_info:
            app_info['md5'] = str(app_info['md5'])

        app.app_file_size = app_info.get("buff_length")
        app.download_url = epk_filename
        db.session.commit()

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

        update_information(real_ip, package.id)

        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()