#!/usr/bin/env python
# -*- coding:utf-8 -*-
# project: 5月
# author: liuyu
# date: 2020/5/7
import binascii
import datetime
import logging
import os
import time

from django.core.cache import cache

from api.models import UserInfo, AppReleaseInfo, AppScreenShot, Token, UserAdDisplayInfo
from api.utils.modelutils import get_app_d_count_by_app_id, get_user_storage_obj
from api.utils.signalutils import run_xsign_migrate_data, run_xsign_clean_data
from common.base.baseutils import get_real_ip_address
from common.cache.storage import UserTokenCache, TaskProgressCache
from common.libs.storage.localApi import LocalStorage
from common.utils.caches import consume_user_download_times
from common.utils.storage import Storage
from common.utils.token import generate_alphanumeric_token_of_length
from fir_ser.settings import MEDIA_ROOT

logger = logging.getLogger(__name__)


def upload_oss_default_head_img(user_obj, storage_obj):
    head_img_full_path = os.path.join(MEDIA_ROOT, "head_img.jpeg")
    if storage_obj:
        storage_obj = Storage(user_obj, storage_obj)
        return storage_obj.upload_file(head_img_full_path)


def check_username_exists(username):
    user_obj = UserInfo.objects.filter(username=username).values("username").first()
    if user_obj and user_obj['username'] == username:
        return True
    return False


def get_random_username(length=16):
    username = generate_alphanumeric_token_of_length(length)
    if check_username_exists(username):
        return get_random_username(length)
    return username


def get_filename_from_apptype(filename, apptype):
    if apptype == 0:
        filename = filename + '.apk'
    else:
        filename = filename + '.ipa'
    return filename


def delete_local_files(filename, apptype=None):
    storage = LocalStorage("localhost", False)
    if apptype is not None:
        filename = get_filename_from_apptype(filename, apptype)
    try:
        return storage.del_file(filename)
    except Exception as e:
        logger.error(f"delete file {filename} failed  Exception  {e}")


def delete_app_screenshots_files(storage_obj, app_obj):
    for screenshot_obj in AppScreenShot.objects.filter(app_id=app_obj).all():
        storage_obj.delete_file(screenshot_obj.screenshot_url)
        screenshot_obj.delete()


def change_storage_and_change_head_img(user_obj, new_storage_obj, clean_old_data=True):
    if user_obj.head_img == 'head_img.jpeg':
        clean_old_data = False
    migrating_storage_file_data(user_obj, user_obj.head_img, new_storage_obj, clean_old_data)
    change_storage_and_change_advert_img(user_obj, new_storage_obj, clean_old_data)


def change_storage_and_change_advert_img(user_obj, new_storage_obj, clean_old_data=True):
    for user_advert_obj in UserAdDisplayInfo.objects.filter(user_id=user_obj, ad_pic__regex='.+'):
        if len(user_advert_obj.ad_pic) > 5:
            migrating_storage_file_data(user_obj, user_advert_obj.ad_pic, new_storage_obj, clean_old_data)


def download_files_form_oss(storage_obj, org_file, force=False):
    with cache.lock(f"download_files_form_oss_{org_file}", timeout=60 * 30):
        if os.path.isfile(org_file) and not force:
            return True
        if storage_obj.download_file(os.path.basename(org_file), org_file + ".check.tmp"):
            if os.path.isfile(org_file) and os.path.exists(org_file + ".check.tmp"):
                os.remove(org_file)
            if os.path.exists(org_file + ".check.tmp"):
                os.rename(os.path.join(org_file + ".check.tmp"), org_file)
                return True
        return False


def check_storage_is_new_storage(user_obj, new_storage_obj):
    old_storage_obj = Storage(user_obj)
    if not new_storage_obj:
        new_storage_obj = Storage(user_obj, None, True)
    else:
        new_storage_obj = Storage(user_obj, new_storage_obj)
    if old_storage_obj.get_storage_uuid() == new_storage_obj.get_storage_uuid():
        return False
    return True


def migrating_storage_file_data(user_obj, filename, new_storage_obj, clean_old_data=True):
    local_file_full_path = os.path.join(MEDIA_ROOT, filename)
    if filename == 'head_img.jpeg':
        return True
    storage_obj = get_user_storage_obj(user_obj)
    if storage_obj.storage_type == 2:
        storage_obj.download_auth_type = 2
        old_oss_storage_obj = Storage(user_obj, storage_obj, prefix='migrate_storage')
    else:
        old_oss_storage_obj = Storage(user_obj, prefix='migrate_storage')

    if not new_storage_obj:
        storage_obj = get_user_storage_obj(user_obj, default=True)
        if storage_obj.storage_type == 2:
            storage_obj.download_auth_type = 2
            new_oss_storage_obj = Storage(user_obj, storage_obj, prefix='migrate_storage')
        else:
            new_oss_storage_obj = Storage(user_obj, None, True, prefix='migrate_storage')
    else:
        if new_storage_obj.storage_type == 2:
            new_storage_obj.download_auth_type = 2
            new_oss_storage_obj = Storage(user_obj, new_storage_obj, prefix='migrate_storage')
        else:
            new_oss_storage_obj = Storage(user_obj, new_storage_obj, prefix='migrate_storage')

    if old_oss_storage_obj.get_storage_uuid() == new_oss_storage_obj.get_storage_uuid():
        # 同一个存储，无需迁移数据
        return True

    if old_oss_storage_obj.get_storage_type() == 3:
        if new_oss_storage_obj.get_storage_type() == 3:
            # 都是本地存储，无需操作
            return True
        else:
            # 本地向云存储上传,并删除本地数据
            res = new_oss_storage_obj.upload_file(local_file_full_path)
            if clean_old_data:
                return delete_local_files(filename)
            return res
    else:
        if new_oss_storage_obj.get_storage_type() == 3:
            # 云存储下载 本地，并删除云存储
            if download_files_form_oss(old_oss_storage_obj, local_file_full_path, True):
                if clean_old_data:
                    return old_oss_storage_obj.delete_file(filename)
                return True
        else:
            # 云存储互传，先下载本地，然后上传新云存储，删除本地和老云存储
            if download_files_form_oss(old_oss_storage_obj, local_file_full_path, True):
                res1 = new_oss_storage_obj.upload_file(local_file_full_path)
                res2 = delete_local_files(filename)
                if clean_old_data:
                    return old_oss_storage_obj.delete_file(filename)
                return res1 and res2


def migrating_storage_data(user_obj, new_storage_obj, clean_old_data):
    with cache.lock(f"migrating_storage_data_{user_obj.uid}", timeout=60 * 60 * 24):
        task_cache = TaskProgressCache('migrating_storage_data', user_obj.uid)
        app_release_queryset = AppReleaseInfo.objects.filter(app_id__user_id=user_obj)
        cache_data = task_cache.get_storage_cache()
        if not cache_data:
            cache_default_data = {
                's_time': time.time(),
                'release_num': app_release_queryset.count(),
                'migrate_num': 0,
                'target_oss_id': -1 if not new_storage_obj else new_storage_obj.pk
            }
        else:
            logger.warning(f"migrate {user_obj} oss progress is exist. may be is migrating data {cache_data}")

        auth_status = False
        certification = getattr(user_obj, 'certification', None)
        if certification and certification.status == 1:
            auth_status = True
        for app_release_obj in app_release_queryset.all():
            # 迁移APP数据
            filename = get_filename_from_apptype(app_release_obj.release_id, app_release_obj.release_type)
            migrating_storage_file_data(user_obj, filename, new_storage_obj, clean_old_data)
            migrating_storage_file_data(user_obj, app_release_obj.icon_url, new_storage_obj, clean_old_data)
            # 迁移APP 截图
            for screenshot_obj in AppScreenShot.objects.filter(app_id=app_release_obj.app_id).all():
                migrating_storage_file_data(user_obj, screenshot_obj.screenshot_url, new_storage_obj, clean_old_data)
            # 迁移超级签数据
            run_xsign_migrate_data(app_release_obj, user_obj, new_storage_obj, clean_old_data)
            # for apptodev_obj in APPToDeveloper.objects.filter(app_id=app_release_obj.app_id).all():
            #     filename = get_filename_from_apptype(apptodev_obj.binary_file, app_release_obj.release_type)
            #     migrating_storage_file_data(user_obj, filename, new_storage_obj, clean_old_data)
            # 消费下载次数
            cache_default_data['migrate_num'] += 1
            task_cache.set_storage_cache(cache_default_data)
            amount = get_app_d_count_by_app_id(app_release_obj.app_id.app_id, user_obj)
            consume_user_download_times(user_obj.pk, app_release_obj.app_id, amount, auth_status)
        task_cache.del_storage_cache()
        return True


def clean_storage_data(user_obj, storage_obj=None):
    storage_obj = Storage(user_obj, storage_obj)
    logger.info(f"{user_obj} clean_storage_data {storage_obj}")
    for app_release_obj in AppReleaseInfo.objects.filter(app_id__user_id=user_obj).all():
        storage_obj.delete_file(app_release_obj.release_id, app_release_obj.release_type)
        storage_obj.delete_file(app_release_obj.icon_url)
        for screenshot_obj in AppScreenShot.objects.filter(app_id=app_release_obj.app_id).all():
            storage_obj.delete_file(screenshot_obj.screenshot_url)
        run_xsign_clean_data(app_release_obj, storage_obj)
        # for apptodev_obj in APPToDeveloper.objects.filter(app_id=app_release_obj.app_id).all():
        #     storage_obj.delete_file(apptodev_obj.binary_file, app_release_obj.release_type)
    return True


def set_user_token(user_obj, request):
    key = binascii.hexlify(os.urandom(32)).decode()
    now = datetime.datetime.now()
    user_info = UserInfo.objects.get(pk=user_obj.pk)
    UserTokenCache(key).set_storage_cache({'uid': user_info.uid, 'username': user_info.username}, 3600 * 24 * 7)
    Token.objects.create(user=user_obj,
                         **{"access_token": key, "created": now, "remote_addr": get_real_ip_address(request)})
    return key, user_info


def clean_user_token_and_cache(user_obj, white_token_list=None):
    if white_token_list is None:
        white_token_list = []
    for token_obj in Token.objects.filter(user=user_obj):
        if token_obj.access_token in white_token_list:
            continue
        UserTokenCache(token_obj.access_token).del_storage_cache()
        token_obj.delete()
