#! /usr/bin/env python
# -*- coding: utf-8 -*-
import json
from django.db.models import Q

from gm_types.gaia import (
    USER_GENDER,
    SKIN_DATA_SOURCE,
)
from gm_types.error import ERROR
from gm_types.face.enum import FACE_SKIN_RESULT_VERSION
from rpc.decorators import bind, bind_context
from rpc.tool.error_code import gen
from api.models.face import SkinResult, FaceSkinResult, SkinResultTag, SkinResultExtra
from api.tool.user_tool import get_user_from_context
from api.tasks.push_task import ai_push_tags_task
from api.services.skin_service import (
    AcneService,
    HeiTouService,
    HeiYanQuanService,
    SkinAgeService,
    SkinOilService,
    SkinColorService,
    SmoothLevelService,
    ActWrinklesService,
    EyeBagService,
    SkinResultService,
    SkinTypeService,
    BlackheadPoreService,
)
from api.models.face import SkinType, BlackheadPore
from rpc.tool.dict_mixin import to_dict



@bind_context('api/face_app/save_skin_result', with_context=True)
def create_skin_result(ctx, data, device_id, image_url, face_diagnose_data=None):
    """
    保存用户测肤的结果
    :param ctx:
    :param data: 测肤结果
    :return:
    """

    user = get_user_from_context(ctx)
    if not data:
        return
    obj = SkinResult()
    obj.user_id = user.id if user else 0
    obj.device_id = device_id or 0
    obj.image_url = image_url

    obj.gender = USER_GENDER.FEMALE if data.get('gender') == 'female' else USER_GENDER.MALE
    obj.total_score = str(data.get('total_score'))
    obj.skin_age = str(data.get('skin_age'))
    obj.skin_color_desc = str(data.get('skin_color_desc'))
    obj.skin_color_level = str(data.get('skin_color_level'))
    obj.skin_color_temperature = str(data.get('skin_color_temperature'))

    obj.equilibrium = str(data.get('skin_radar').get('equilibrium'))
    obj.health = str(data.get('skin_radar').get('health'))
    obj.smooth = str(data.get('skin_radar').get('smooth'))
    obj.tolerance = str(data.get('skin_radar').get('tolerance'))
    obj.uniform = str(data.get('skin_radar').get('uniform'))
    obj.young = str(data.get('skin_radar').get('young'))

    obj.oil_level = str(data.get('oil_level'))
    obj.blackhead_number = str(data.get('blackhead_number'))
    obj.blackhead_severity = str(data.get('blackhead_severity'))
    obj.tzone_oil_shine = str(data.get('tzone_oil_shine'))
    obj.cheek_oil_shine = str(data.get('cheek_oil_shine'))
    obj.chin_oil_shine = str(data.get('chin_oil_shine'))
    obj.pore_severity = str(data.get('pore_severity'))
    obj.coarseness = str(data.get('coarseness'))

    obj.pigmental = str(data.get('dark_circle').get('pigmental'))
    obj.vascular = str(data.get('dark_circle').get('vascular'))
    obj.structural = str(data.get('dark_circle').get('structural'))
    obj.severity = str(data.get('dark_circle').get('severity'))

    obj.acne_json = json.dumps(data.get('acne')) if data.get('acne') else '[]'
    obj.acne_severity = str(data.get('acne_severity'))
    obj.acne_desc = str(data.get('acne_desc'))

    obj.short_oil_level_advice = str(data.get('short_oil_level_advice'))
    obj.short_coarseness_advice = str(data.get('short_coarseness_advice'))
    obj.short_blackhead_advice = str(data.get('short_blackhead_advice'))
    obj.short_acne_advice = str(data.get('short_acne_advice'))
    obj.short_dark_circle_advice = str(data.get('short_dark_circle_advice'))
    obj.face_diagnose = json.dumps(face_diagnose_data or {})

    obj.save()

    return {'id': obj.id}


@bind_context('api/face_app/get_skin_result', with_context=True)
def get_skin_result(ctx, device_id):
    user = get_user_from_context(ctx)
    user_id = user.id if user else 0
    query = Q(device_id=device_id)
    if user_id:
        query = Q(user_id=user_id)
    obj = SkinResult.objects.filter(query).order_by('-id').first()
    if not obj:
        return {}
    return {
        'id': obj.id,
        'total_score': obj.total_score,

        'skin_radar': obj.skin_radar,
        'dark_circle': obj.dark_circle,

        'gender': 'female' if obj.gender == USER_GENDER.FEMALE else 'male',
        'skin_age': obj.skin_age,
        'skin_color_level': obj.skin_color_level,
        'skin_color_desc': obj.skin_color_desc,
        'skin_color_temperature': obj.skin_color_temperature,
        'oil_level': obj.oil_level,
        'blackhead_number': obj.blackhead_number,
        'blackhead_severity': obj.blackhead_severity,
        'tzone_oil_shine': obj.tzone_oil_shine,
        'cheek_oil_shine': obj.cheek_oil_shine,
        'chin_oil_shine': obj.chin_oil_shine,
        'pore_severity': obj.pore_severity,
        'coarseness': obj.coarseness,

        'acne': obj.acne,
        'acne_severity': obj.acne_severity,
        'acne_desc': obj.acne_desc,

        'short_oil_level_advice': obj.short_oil_level_advice,
        'short_coarseness_advice': obj.short_coarseness_advice,
        'short_blackhead_advice': obj.short_blackhead_advice,
        'short_acne_advice': obj.short_acne_advice,
        'short_dark_circle_advice': obj.short_dark_circle_advice,

        'image_url': obj.image_url,
        'device_id': obj.device_id,
        'user_id': obj.user_id,
        'created_time': obj.created_time.strftime("%Y-%m-%d %H:%M:%S"),
        'face_diagnose': json.loads(obj.face_diagnose) if obj.face_diagnose else {},
    }


@bind_context('api/face_app/get_face_skin_result', with_context=True)
def get_face_skin_result(ctx, device_id):
    user = get_user_from_context(ctx)
    user_id = user.id if user else 0
    query = Q(device_id=device_id)
    if user_id:
        query = Q(user_id=user_id)
    obj = FaceSkinResult.objects.filter(query).order_by('-id').first()
    if not obj:
        return {}
    return {
        'id': obj.id,
        'skin_color': obj.skin_color,
        'skin_age': obj.skin_age,
        'eye_bags': obj.eye_bags,
        'dark_circle': obj.dark_circle,
        'forehead_wrinkle': obj.forehead_wrinkle,
        'forehead_wrinkle_raw': obj.forehead_wrinkle_raw,
        'crows_feet': obj.crows_feet,
        'crows_feet_raw': obj.crows_feet_raw,
        'eye_finelines': obj.eye_finelines,
        'glabella_wrinkle': obj.glabella_wrinkle,
        'wrinkles': obj.wrinkles,
        'wrinkles_raw': obj.wrinkles_raw,
        'skin_oil': obj.skin_oil,
        'black_head': obj.black_head,
        'pores': obj.pores,
        'acne': obj.acne,
        'acne_raw': obj.acne_raw,
        'mole': obj.mole,
        'skin_spot': obj.skin_spot,
        "tractate_id": obj.tractate_id,
        "version": obj.version,

        'image_url': obj.image_url,
        'device_id': obj.device_id,
        'user_id': obj.user_id,
        'created_time': obj.created_time.strftime("%Y-%m-%d %H:%M:%S"),
    }


@bind("api/skin_check/conf")
def get_skin_conf_info(filter_data):
    """
    获取测肤后台配置信息
    :param filter_data:  不同类型筛选字段集合 {"skin_age": {}, "skin_oil": {}} ……
    :return:
    """
    result = {
        "skin_age": SkinAgeService.get_skin_age_info(filter_data.get("skin_age", {})),  # 肤龄
        "skin_oil": SkinOilService.get_skin_oil_info(filter_data.get("skin_oil", {})),  # 油脂
        "black_head": HeiTouService.get_heitou_info(filter_data.get("black_head", {})),  # 黑头
        "acne": AcneService.get_acne_info(filter_data.get("acne", {})),  # 痘痘
        "smooth": SmoothLevelService.get_smooth_level_info(filter_data.get("smooth", {})),  # 光滑度
        "dark_circle": HeiYanQuanService.get_dark_circle_info(filter_data.get("dark_circle", {})),  # 黑眼圈
        "skin_color": SkinColorService.get_skin_color_info(filter_data.get("skin_color", {})),  # 肤色
        "wrinkles": ActWrinklesService.get_wrinkles_info(filter_data.get("wrinkles", {})),  # 法令纹,
        "eye_bags": EyeBagService.get_eye_bag_info(filter_data.get("eye_bags", {})),  # 眼袋,
    }

    return result


@bind("api/ks_skin_type_check/conf", with_context=True)
def get_ks_skin_type_conf_info(ctx, filter_data, device_id, from_last=False):
    """
    获取旷视测肤后台配置信息（替换原有'以息'接口）
    """
    user = get_user_from_context(ctx)

    user_id = user.id if user else 0
    query = Q(device_id=device_id)

    if user_id:
        query = Q(user_id=user_id)
    if from_last is True:
        last_data = True if SkinResult.objects.filter(query).exists() else False
        new_data = True if FaceSkinResult.objects.filter(query).count() > 1 else False
        status = True if last_data or new_data else False
    else:
        status = True if FaceSkinResult.objects.filter(query).count() > 1 else False
    result = {
        "skin_color": SkinTypeService.get_skintype_info(filter_data.get("skin_color", {})),  # 肤色
        "skin_oil": SkinTypeService.get_skintype_info(filter_data.get("skin_oil", {})),  # 出油情况
        "dark_circle": SkinTypeService.get_skintype_info(filter_data.get("dark_circle", {})),  # 黑眼圈
        "acne": SkinTypeService.get_skintype_info(filter_data.get("acne", {})),  # 痘痘
        "skin_spot": SkinTypeService.get_skintype_info(filter_data.get("skin_spot", {})),  # 斑
        "mole": SkinTypeService.get_skintype_info(filter_data.get("mole", {})),  # 痣
        # "eye_bags": SkinTypeService.get_skintype_info(filter_data.get("eye_bags", {})),  # 眼袋
        # "eye_finelines": SkinTypeService.get_skintype_info(filter_data.get("eye_finelines", {})),  # 眼部细纹
        # "crows_feet": SkinTypeService.get_skintype_info(filter_data.get("crows_feet", {})),  # 鱼尾纹
        # "wrinkles": SkinTypeService.get_skintype_info(filter_data.get("wrinkles", {})),  # 法令纹
        # "glabella_wrinkle": SkinTypeService.get_skintype_info(filter_data.get("glabella_wrinkle", {})),  # 眉间纹
        # "forehead_wrinkle": SkinTypeService.get_skintype_info(filter_data.get("forehead_wrinkle", {})),  # 抬头纹

        "skin_age": SkinAgeService.get_skin_age_info(filter_data.get("skin_age", {})),  # 肤龄
        "black_head": BlackheadPoreService.get_blackheadpore_info(filter_data.get("black_head", {})),  # 黑头毛孔
        "status": status,
    }
    updata_dict = {
        "eye_bags": SkinTypeService.get_skintype_info(filter_data.get("eye_bags", {})),  # 眼袋
        "wrinkles": SkinTypeService.get_skintype_info(filter_data.get("wrinkles", {})),  # 法令纹
        "forehead_wrinkle": SkinTypeService.get_skintype_info(filter_data.get("forehead_wrinkle", {})),  # 抬头纹
        "glabella_wrinkle": SkinTypeService.get_skintype_info(filter_data.get("glabella_wrinkle", {})),  # 眉间纹
        "crows_feet": SkinTypeService.get_skintype_info(filter_data.get("crows_feet", {})),  # 鱼尾纹
        "eye_finelines": SkinTypeService.get_skintype_info(filter_data.get("eye_finelines", {})),  # 眼部细纹
    }
    if status:
        result.update(updata_dict)
    return result


@bind("api/skin_conf/get_conf_info")
def get_skin_conf_info_by_type_content(type_content, type_value):
    """
    通过部位名称获取旷视测肤后台配置信息
    """

    obj = SkinType.objects.filter(type_content=type_content, type_value=type_value, is_online=True).first()

    result = to_dict(obj, excludes=["is_online", "created_time", "updated_time"])

    return result


@bind("api/skin_conf/get_heitou_conf")
def get_heitou_conf(blackhead_level, pore_level):
    """
    获取黑头旷视测肤后台配置信息
    """

    obj = BlackheadPore.objects.filter(blackhead_level=blackhead_level, pore_level=pore_level, is_online=True).first()

    result = to_dict(obj, excludes=["is_online", "created_time", "updated_time"])

    return result


@bind("api/skin_check/get_all_info")
def get_skin_check_all_info():
    result = {
        "smooth_info": SmoothLevelService.get_smooth_all_images_info(),
    }

    return result


@bind("api/ks_skin_type/get_all_info")
def get_ks_skin_type_all_info():
    result = {
        "skintype_info": SkinTypeService.get_skintype_all_images_info(),
    }

    return result


@bind("api/skin_check/has_lastest_record", with_context=True)
def skin_check_has_lastest_record(ctx, device_id):
    """
    是否有测肤记录
    :param ctx:
    :param device_id:
    :return:
    """
    user = get_user_from_context(ctx)

    user_id = user.id if user else 0
    query = Q(device_id=device_id)

    if user_id:
        query = Q(user_id=user_id)

    status = SkinResult.objects.filter(query).exists()


    has_data_v2 = FaceSkinResult.objects.filter(query & Q(version=FACE_SKIN_RESULT_VERSION.V2)).exists()

    return {
        "status": True if status else False,
        "has_data_v2": has_data_v2
    }


@bind("api/skin_check/get_record_by_id")
def get_skin_check_record_by_id(skin_id, device_id, user_id=0, skin_data_source=SKIN_DATA_SOURCE.YIXI):
    """
    通过测肤记录的ID 获取数据
    ps：这里考虑安全性，需要同时查询设备ID；若是登录用户则再加上用户ID。防止别人获取表中数据！！！
    :param skin_id:
    :param device_id:
    :param user_id:
    :param skin_data_source: 是否使用旷视数据
    :return:
    """
    result = {}
    if not all([skin_id, device_id]):
        return result

    filter_query = Q(pk=skin_id, device_id=device_id)
    if user_id:
        filter_query &= Q(user_id=user_id)

    if skin_data_source == SKIN_DATA_SOURCE.YIXI:
        model_ = SkinResult
        format_func = SkinResultService.format_skin_result

    elif skin_data_source == SKIN_DATA_SOURCE.KUANGSHI:
        model_ = FaceSkinResult
        format_func = SkinResultService.format_ks_skin_result

    else:
        return result

    _obj = SkinResultService.get_objs_by_query_and_order(
        model_set=model_,
        query=filter_query
    ).first()

    return format_func(_obj)


@bind_context('api/face_app/save_face_skin_result', with_context=True)
def create_face_skin_result(ctx, data, device_id, image_url, version=FACE_SKIN_RESULT_VERSION.V2):
    """
    保存用户测肤的结果
    :param ctx:
    :param data: 测肤结果
    :return:
    """

    user = get_user_from_context(ctx)
    if not data:
        return

    if not SkinResult.objects.filter(device_id=device_id).exists() and not FaceSkinResult.objects.filter(
            device_id=device_id).exists():
        ai_push_tags_task.delay(device_id)

    obj = FaceSkinResult()
    obj.user_id = user.id if user else 0
    obj.device_id = device_id or 0
    obj.image_url = image_url

    obj.skin_color = data.get("skin_color")
    obj.skin_age = data.get("skin_age")
    obj.eye_bags = data.get("eye_bags")
    obj.dark_circle = data.get("dark_circle")
    obj.forehead_wrinkle = data.get("forehead_wrinkle")
    obj.forehead_wrinkle_raw = data.get("forehead_wrinkle_raw", 0)
    obj.crows_feet = data.get("crows_feet")
    obj.crows_feet_raw = data.get("crows_feet_raw", 0)
    obj.eye_finelines = data.get("eye_finelines")
    obj.glabella_wrinkle = data.get("glabella_wrinkle")
    obj.wrinkles = data.get("wrinkles")
    obj.wrinkles_raw = data.get("wrinkles_raw", 0)
    obj.skin_oil = data.get("skin_oil")
    obj.black_head = data.get("black_head")
    obj.pores = data.get("pores")
    obj.acne = data.get("acne")
    obj.acne_raw = data.get("acne_raw", 0)
    obj.mole = data.get("mole")
    obj.skin_spot = data.get("skin_spot")
    obj.version = version
    obj.save()
    return {'id': obj.id}


@bind('api/face_app/save_skin_tag_record')
def save_skin_tag_record(skin_id, tag_ids):
    """
    保存用户测肤时选择的状态标签
    :param skin_id: 测肤结果id
    :param tag_ids: 标签id列表
    :return:
    """
    if SkinResultTag.objects.filter(result_id=skin_id).exists():
        gen(ERROR.FACE_TAG_EXIT)

    if not FaceSkinResult.objects.filter(id=skin_id).exists():
        gen(ERROR.FACE_RES_NOT_FOUND)

    SkinResultTag.objects.bulk_create([
        SkinResultTag(
            result_id=skin_id,
            tag_id=tag_id,
        ) for tag_id in tag_ids
    ])

    return 1


@bind('api/face_app/get_skin_tag_record')
def get_skin_tag_record(skin_id):
    """
    获取用户测肤时选择的状态标签
    :param skin_id: 测肤结果id
    :return: {tag_ids: 标签id列表}
    """
    tag_ids = list(SkinResultTag.objects.filter(result_id=skin_id).values_list('tag_id', flat=True))

    return {"tag_ids": tag_ids}


@bind('api/face_app/save_skin_tractate_record')
def save_skin_tractate_record(skin_id, tractate_id):
    """
    保存测肤打卡帖记录
    :param skin_id: 测肤结果id
    :param tractate_id: 打卡帖id
    :return:
    """
    try:
        obj = FaceSkinResult.objects.get(id=skin_id)
    except:
        obj = None

    if not obj:
        gen(ERROR.FACE_RES_NOT_FOUND)

    if obj.tractate_id:
        gen(ERROR.FACE_TRACTATE_EXIT)

    obj.tractate_id = tractate_id
    obj.save()

    return obj.id


@bind('api/face_app/get_skin_send_msg_record')
def get_skin_send_msg_record(skin_id):
    """
    获取测肤结果是否发送私信
    :param skin_id: 测肤结果id
    :return: {send_msg: 是否发送过私信}
    """
    try:
        obj = SkinResultExtra.objects.get(result_id=skin_id)
    except:
        obj = None

    if not obj:
        res = {}
    else:
        res = {"send_msg": obj.send_msg}

    return res


@bind('api/face_app/save_skin_send_msg_record')
def save_skin_send_msg_record(skin_id):
    """
    保存测肤结果 发送私信记录
    :param skin_id: 测肤结果id
    :return:
    """
    try:
        extra_obj = SkinResultExtra.objects.get(result_id=skin_id)
    except:
        extra_obj = None

    if extra_obj and extra_obj.send_msg:
        gen(ERROR.UNIVERSAL)

    try:
        obj = FaceSkinResult.objects.get(id=skin_id)
    except:
        gen(ERROR.FACE_RES_NOT_FOUND)

    if not extra_obj:
        obj = SkinResultExtra()
        obj.result_id = skin_id
        obj.send_msg = True
        obj.save()
    else:
        extra_obj.send_msg = True
        extra_obj.save()

    return 1


@bind('api/tractate_id/by_skin_res_id')
def get_tractate_id(skin_id=None, device_id=None, user_id=None):
    result = {
        'tractate_id': None
    }

    if skin_id:
        query = Q(id=skin_id)
    elif user_id:
        query = Q(user_id=user_id)
    elif device_id:
        query = Q(device_id=device_id)
    else:
        return result

    face_result = FaceSkinResult.objects.filter(query).last()
    if face_result:
        result['tractate_id'] = face_result.tractate_id
    return result
