# coding: utf-8

from datetime import datetime
import json

import numpy as np
from django.db.models import Q
from django.core.paginator import Paginator
from django.forms.models import model_to_dict

from api.models.face.cheek_style import (
	CheekStyle,
	CheekStyleSample,
	GoldSkinInfo,
	GoldPercentDefine,
	PointLocation,
	FaceGoldValue,
	FeatureWeightValue,
	UserPlasticHistory,
	UserCheekTypesFeasibility,
	CheekStyleClassifyMap,
)

from gm_types.face.enum import GoldValueDefineType


def fork_model_to_dict(instance):

	sink_instance = model_to_dict(instance)
	need_time_keys = [
		"create_time",
		"update_time"
	]
	for time_key in need_time_keys:
		if hasattr(instance, time_key):
			value = getattr(instance, time_key)
			sink_instance[time_key] = value.strftime("%Y-%m-%d %H:%M:%S")
	for key, value in sink_instance.items():
		if isinstance(value, datetime):
			sink_instance[key] = value.strftime("%Y-%m-%d %H:%M:%S")
	return sink_instance


def page_instance(model_instances, page, page_size):
	paginator = Paginator(model_instances, page_size)
	total_page_num = paginator.num_pages
	total_count = paginator.count
	instance_data = [instance for instance in paginator.page(page)]
	result = {
		"data": instance_data,
		"page": page,
		"page_size": len(instance_data),
		"total_count": total_count,
		"total_page_num": total_page_num
	}
	return result


class PercentDefinitionsService:
	def __init__(self):
		pass

	def gold_percents(self, is_online=None):
		if is_online is None:
			gold_percent_defines = GoldPercentDefine.objects.filter()
		else:
			gold_percent_defines = GoldPercentDefine.objects.filter(is_online=is_online)
		gpd_ids = [item.id for item in gold_percent_defines]

		gold_skin_infos = GoldSkinInfo.objects.filter(
			gold_percent_define_id__in=gpd_ids
		)
		point_locations = PointLocation.objects.filter(
			gold_percent_define_id__in=gpd_ids
		)
		gpd_id2gold_skin_info = {item.gold_percent_define_id: item for item in gold_skin_infos}
		gpd_id2point_locations = dict()
		for point_location in point_locations:
			gpd_id2point_locations.setdefault(
				point_location.gold_percent_define_id, []
			).append(fork_model_to_dict(point_location))

		result = list()
		for gold_percent_define in gold_percent_defines:
			gpd_info = dict()
			gpd_info["id"] = gold_percent_define.id
			gpd_info["name"] = gold_percent_define.name
			gpd_info["define_type"] = gold_percent_define.define_type
			if gold_percent_define.define_type == GoldValueDefineType.PERCENT:
				gpd_point_locations = gpd_id2point_locations.get(gold_percent_define.id)
				if not gpd_point_locations or len(gpd_point_locations) != 2:
					continue
				gpd_info["point_locations"] = gpd_point_locations
			elif gold_percent_define.define_type == GoldValueDefineType.ANGLE:
				gpd_point_locations = gpd_id2point_locations.get(gold_percent_define.id)
				if not gpd_point_locations or len(gpd_point_locations) != 1:
					continue
				gpd_info["point_locations"] = gpd_point_locations
			else:
				gold_skin_info = gpd_id2gold_skin_info.get(gold_percent_define.id)
				if not gold_skin_info:
					continue

				gpd_info["gold_skin_info"] = {
					"skin_type": gold_skin_info.skin_type,
					"skin_type_max_diff_value": gold_skin_info.skin_type_max_diff_value,
					"skin_type_value_negative": gold_skin_info.skin_type_value_negative,
				}
			result.append(gpd_info)
		return result


class CheekStyleService:
	def __init__(self):
		pass

	def query_cheek_style_classify_maps(self):
		cheek_style_classifies = CheekStyleClassifyMap.objects.filter(
			is_online=1,
			deleted=0
		)
		result = dict()
		for csc in cheek_style_classifies:
			result.setdefault(
				csc.cheek_style_classify_id, []
			).append(fork_model_to_dict(csc))
		return result

	def query_one_cheek_styles(self, cheek_style_id):
		cheek_style = CheekStyle.objects.filter(id=cheek_style_id).first()
		data = dict()
		if cheek_style:
			data["id"] = cheek_style.id
			data["name"] = cheek_style.name
			data["image_url"] = cheek_style.image_url
			data["is_online"] = cheek_style.is_online
		return data

	def add_user_cheek_types_feasibility(
			self, cheek_style_id,
			user_plastic_history_id,
			feasibility_info
	):
		user_cheek_style_feasibility = UserCheekTypesFeasibility()
		user_cheek_style_feasibility.cheek_style_id = cheek_style_id
		user_cheek_style_feasibility.user_plastic_history_id = user_plastic_history_id
		user_cheek_style_feasibility.feasibility_info = json.dumps(feasibility_info)
		user_cheek_style_feasibility.save()
		return user_cheek_style_feasibility.id

	def add_user_plastic_history(
			self, url_key, image_url,
			proportion,
			gold_values,
			megvii_landmark="",
			byte_dance_landmark="",
			user_id=0,
			device_id=0
	):
		user_plastic_history = UserPlasticHistory()
		user_plastic_history.url_key = url_key
		user_plastic_history.image_url = image_url
		user_plastic_history.megvii_landmark = megvii_landmark
		user_plastic_history.byte_dance_landmark = byte_dance_landmark
		user_plastic_history.proportion = proportion
		user_plastic_history.gold_values = gold_values
		user_plastic_history.user_id = user_id
		user_plastic_history.device_id = device_id
		user_plastic_history.save()
		return user_plastic_history.id

	def get_last_user_plastic_history(self, user_id, device_id):
		# 产品：不管谁登陆，都按照设备号查找上次记录

		user_plastic_history = UserPlasticHistory.objects.filter(
			device_id=device_id
		).order_by('-id').first()

		if user_plastic_history:
			ret = model_to_dict(user_plastic_history)
		else:
			ret = {}
		return ret

	def update_cheek_style_gold_values(
			self, cheek_style_id, name, image_url, is_online, key, value):
		cheek_style = CheekStyle.objects.filter(id=cheek_style_id).first()
		if not cheek_style:
			return
		if name:
			cheek_style.name = name
		if image_url:
			cheek_style.image_url = image_url
		if is_online is not None:
			cheek_style.is_online = is_online
		cheek_style.save()

		if key and value is not None:
			cheek_style_sample = CheekStyleSample.objects.filter(
				cheek_style_id=cheek_style_id,
				deleted=0,
				is_sample=0,
			).first()
			if cheek_style_sample:
				gpd = GoldPercentDefine.objects.filter(id=int(key)).first()
				if gpd:
					fgv = FaceGoldValue.objects.filter(
						cheek_style_sample_id=cheek_style_sample.id,
						gold_percent_define_id=gpd.id
					).first()
					if not fgv:
						fgv = FaceGoldValue()
						fgv.gold_percent_define_id = gpd.id
						fgv.cheek_style_sample_id = cheek_style_sample.id
					fgv.percent_value = value
					fgv.save()
		return cheek_style_id

	def add_new_cheek_style(self, name, image_url, is_online):
		cheek_style = CheekStyle.objects.filter(name=name).first()
		if cheek_style:
			return
		cheek_style = CheekStyle()
		cheek_style.name = name
		cheek_style.is_online = is_online
		cheek_style.image_url = image_url
		cheek_style.save()

		css = CheekStyleSample()
		css.cheek_style_id = cheek_style.id
		css.image_url = image_url
		css.is_sample = 0
		css.deleted = 0
		css.discern_status = 1
		css.save()

		for gdf in GoldPercentDefine.objects.all():
			fgv = FaceGoldValue()
			fgv.cheek_style_sample_id = css.id
			fgv.gold_percent_define_id = gdf.id
			fgv.percent_value = 0
			fgv.save()
		return cheek_style.id

	def page_cheek_styles(self, page, page_size, name, cheek_style_id):
		filters = list()
		if name:
			filters.append(Q(name=name))
		if cheek_style_id:
			filters.append(Q(id=cheek_style_id))

		model_instances = CheekStyle.objects.filter(*filters)
		cheek_styles_infos = page_instance(model_instances, page, page_size)
		cheek_style_ids = [csi.id for csi in cheek_styles_infos["data"]]
		page_info = {
			"page": page,
			"page_size": cheek_styles_infos["page_size"],
			"total_count": cheek_styles_infos["total_count"],
			"total_page_num": cheek_styles_infos["total_page_num"],
		}

		cheek_style_samples = CheekStyleSample.objects.filter(
			cheek_style_id__in=cheek_style_ids,
			is_sample=0,
			deleted=0,
		)
		cheek_style_samples_ids = list()
		cs_id2css_id = dict()
		for css in cheek_style_samples:
			cheek_style_samples_ids.append(css.id)
			cs_id2css_id[css.cheek_style_id] = css.id

		face_gold_values = FaceGoldValue.objects.filter(
			cheek_style_sample_id__in=cheek_style_samples_ids
		)
		css_id2fgv_obj = dict()
		for fgv in face_gold_values:
			css_id2fgv_obj.setdefault(fgv.cheek_style_sample_id, []).append(fgv)

		headers = [
			{
				"key": "cheek_style_id",
				"name": "id",
				"index": -2,
				"adaptable": 0
			},
			{
				"key": "cheek_style_name",
				"name": "风格脸名称",
				"index": -1,
				"adaptable": 0
			},
			{
				"key": "is_online",
				"name": "是否上线",
				"index": 0,
				"adaptable": 0
			}
		]
		gpd_id2gpd_obj = dict()
		for gold_percent_define in GoldPercentDefine.objects.filter(is_online=1):
			gpd_id2gpd_obj[gold_percent_define.id] = gold_percent_define
			headers.append({
				"key": str(gold_percent_define.id),
				"name": gold_percent_define.name,
				"index": gold_percent_define.id,
				"adaptable": 1
			})
		headers.sort(key=lambda x: x["index"])

		gold_percent_values = list()
		for cheek_style in cheek_styles_infos["data"]:
			cheek_style_sample_id = cs_id2css_id.get(cheek_style.id)
			fgv_objs = css_id2fgv_obj.get(cheek_style_sample_id, [])
			gpd_id2percent_value = {
				fgv.gold_percent_define_id: fgv.percent_value
				for fgv in fgv_objs
			}
			row = {
				"cheek_style_id": cheek_style.id,
				"cheek_style_name": cheek_style.name,
				"is_online": cheek_style.is_online,
			}
			for gpd_id, gpd_obj in gpd_id2gpd_obj.items():
				row[str(gpd_obj.id)] = round(gpd_id2percent_value.get(gpd_id, 0), 2)
			gold_percent_values.append(row)

		return {"gold_percent_values": gold_percent_values, "headers": headers, "page_info": page_info}

	def query_cheek_styles_all(self):
		cheek_styles = self.query_cheek_styles(is_online=True)
		cheek_style_ids = [cs.id for cs in cheek_styles]
		cheek_style_samples = CheekStyleSample.objects.filter(
			cheek_style_id__in=cheek_style_ids,
			is_sample=False,
			deleted=0
		)
		cheek_style_id2sample_id = {
			css.cheek_style_id: css.id for css in cheek_style_samples
		}

		face_gold_values = FaceGoldValue.objects.filter(
			cheek_style_sample_id__in=[cts.id for cts in cheek_style_samples]
		)
		cheek_style_sample_id2gold_values = dict()
		for gold_value in face_gold_values:
			cheek_style_sample_id2gold_values.setdefault(
				gold_value.cheek_style_sample_id, []
			).append(
				{
					"gold_percent_define_id": gold_value.gold_percent_define_id,
					"percent_value": gold_value.percent_value
				}
			)
		cheek_style_classifies = CheekStyleClassifyMap.objects.filter(
			cheek_style_id__in=cheek_style_ids,
			deleted=0,
			is_online=1,
		)
		cheek_style_id2cheek_style_classify_id = {
			cssm.cheek_style_id: cssm.cheek_style_classify_id for cssm in cheek_style_classifies
		}
		result = list()
		for cheek_style in cheek_styles:
			cheek_style_sample_id = cheek_style_id2sample_id.get(cheek_style.id)
			if cheek_style_sample_id:
				gold_values = cheek_style_sample_id2gold_values.get(cheek_style_sample_id, [])
			else:
				gold_values = []

			cheek_style_classify_id = cheek_style_id2cheek_style_classify_id.get(cheek_style.id)
			if not cheek_style_classify_id:
				continue

			cheek_style_info = dict()
			cheek_style_info["id"] = cheek_style.id
			cheek_style_info["name"] = cheek_style.name
			cheek_style_info["image_url"] = cheek_style.image_url
			cheek_style_info["gold_values"] = gold_values
			cheek_style_info["category"] = cheek_style_classify_id
			cheek_style_info["is_online"] = cheek_style.is_online
			result.append(cheek_style_info)
		return result

	def query_cheek_styles(self, is_online=None):
		if is_online is None:
			cheek_styles = CheekStyle.objects.all()
		else:
			cheek_styles = CheekStyle.objects.filter(is_online=is_online)
		return cheek_styles

	def calculate_gold_values(self, cheek_style_id):
		cheek_style = CheekStyle.objects.filter(id=cheek_style_id).first()
		if not cheek_style:
			return
		cheek_style_samples = CheekStyleSample.objects.filter(
			cheek_style_id=cheek_style_id,
			deleted=0,
		)
		cheek_style_sample_ids = [
			css.id for css in cheek_style_samples if css.is_sample == 1]

		cheek_style_avg_sample_id = None
		for css in cheek_style_samples:
			if css.is_sample == 0:
				cheek_style_avg_sample_id = css.id
				break

		result = dict()
		face_gold_values = FaceGoldValue.objects.filter(
			cheek_style_sample_id__in=cheek_style_sample_ids
		)
		gold_percent_define_id2gold_value = dict()
		for gold_value in face_gold_values:
			gold_percent_define_id2gold_value.setdefault(
				gold_value.gold_percent_define_id, []
			).append(gold_value.percent_value)

		sample_gold_values = FaceGoldValue.objects.filter(
			cheek_style_sample_id=cheek_style_avg_sample_id
		)
		gpd_id2face_gold_value_obj = {
			fgv.gold_percent_define_id: fgv for fgv in sample_gold_values
		}

		gold_percent_defines = GoldPercentDefine.objects.filter(is_online=1)
		gpd_id2gpd_obj = {gpd.id: gpd for gpd in gold_percent_defines}
		gold_percent_value = dict()
		gold_percent_value["cheek_style_sample_name"] = cheek_style.name
		gold_percent_value["cheek_style_sample_image_url"] = cheek_style.image_url
		for gpd_id, gpd_obj in gpd_id2gpd_obj.items():
			percent_values = gold_percent_define_id2gold_value.get(gpd_id)
			if percent_values:
				avg_value = round(np.mean(percent_values), 2)
			else:
				avg_value = 0

			face_gold_value_obj = gpd_id2face_gold_value_obj.get(gpd_id)
			if not face_gold_value_obj:
				face_gold_value_obj = FaceGoldValue()
				face_gold_value_obj.cheek_style_sample_id = cheek_style_avg_sample_id

			face_gold_value_obj.gold_percent_define_id = gpd_id
			face_gold_value_obj.percent_value = avg_value
			face_gold_value_obj.save()
			gold_percent_value[str(gpd_id)] = avg_value
		result["cheek_style_id"] = cheek_style_id
		result["gold_percent_values"] = gold_percent_value
		return result


class CheekStyleSampleService:
	def __init__(self):
		pass

	def put_cheek_style_sample_values(self, cheek_style_id, sample_id, image_url):
		cheek_style = CheekStyle.objects.filter(id=cheek_style_id).first()
		if not cheek_style:
			return
		cheek_style_sample = CheekStyleSample.objects.filter(id=sample_id).first()
		if cheek_style_sample:
			cheek_style_sample.image_url = image_url
			cheek_style_sample.save()
			return sample_id
		return -1

	def get_cheek_style_samples(self, cheek_style_id, page=1, page_size=10):
		cheek_style = CheekStyle.objects.filter(id=cheek_style_id).first()
		if not cheek_style:
			return
		model_instances = CheekStyleSample.objects.filter(
			cheek_style_id=cheek_style_id,
			deleted=0,
		)
		cheek_styles_sample_infos = page_instance(model_instances, page, page_size)
		page_info = {
			"page": page,
			"page_size": cheek_styles_sample_infos["page_size"],
			"total_count": cheek_styles_sample_infos["total_count"],
			"total_page_num": cheek_styles_sample_infos["total_page_num"],
		}
		cs_id2css_id = dict()
		cheek_style_samples_ids = list()
		for css in cheek_styles_sample_infos["data"]:
			cheek_style_samples_ids.append(css.id)
			cs_id2css_id[css.cheek_style_id] = css.id

		face_gold_values = FaceGoldValue.objects.filter(
			cheek_style_sample_id__in=cheek_style_samples_ids
		)
		css_id2fgv_obj = dict()
		for fgv in face_gold_values:
			css_id2fgv_obj.setdefault(fgv.cheek_style_sample_id, []).append(fgv)
		headers = [
			{
				"key": "cheek_style_sample_name",
				"name": "风格脸名称",
				"index": -2,
				"adaptable": 0
			},
			{
				"key": "cheek_style_sample_image_url",
				"name": "图片",
				"index": -1,
				"adaptable": 0
			}
		]
		gpd_id2gpd_obj = dict()
		for gold_percent_define in GoldPercentDefine.objects.filter(is_online=1):
			gpd_id2gpd_obj[gold_percent_define.id] = gold_percent_define
			headers.append({
				"key": str(gold_percent_define.id),
				"name": gold_percent_define.name,
				"index": gold_percent_define.id,
				"adaptable": 0
			})
		headers.sort(key=lambda x: x["index"])

		gold_percent_values = list()
		for cheek_style_sample in cheek_styles_sample_infos["data"]:
			fgv_objs = css_id2fgv_obj.get(cheek_style_sample.id, [])
			gpd_id2percent_value = {
				fgv.gold_percent_define_id: fgv.percent_value
				for fgv in fgv_objs
			}
			if cheek_style_sample.is_sample:
				row = {
					"cheek_style_sample_name": u"样本%d" % cheek_style_sample.id,
					"cheek_style_sample_image_url": cheek_style_sample.image_url,
					"id": cheek_style_sample.id
				}
			else:
				row = {
					"cheek_style_sample_name": cheek_style.name,
					"cheek_style_sample_image_url": cheek_style.image_url,
					"id": cheek_style_sample.id
				}
			for gpd_id, gpd_obj in gpd_id2gpd_obj.items():
				row[str(gpd_obj.id)] = round(gpd_id2percent_value.get(gpd_id, 0), 2)
			gold_percent_values.append(row)
		gold_percent_values.sort(key=lambda x: x["id"])
		return {"gold_percent_values": gold_percent_values, "headers": headers, "page_info": page_info}

	def add_cheek_style_sample(self, cheek_style_id, image_url):
		css = CheekStyleSample()
		css.is_sample = 1
		css.cheek_style_id = cheek_style_id
		css.image_url = image_url
		css.discern_status = 0
		css.save()
		return css.id

	def write_cheek_style_sample_value(self, sample_id, gold_values):
		for gold_value in gold_values:
			fgv = FaceGoldValue()
			fgv.gold_percent_define_id = gold_value["gold_percent_define_id"]
			fgv.percent_value = gold_value["percent_value"]
			fgv.cheek_style_sample_id = sample_id
			fgv.save()
		cheek_style_sample = CheekStyleSample.objects.filter(id=sample_id).first()
		if cheek_style_sample:
			cheek_style_sample.discern_status = 1
			cheek_style_sample.save()

	def cheek_style_sample_gold_values(
			self, cheek_style_id, sample_id
	):
		gold_percent_value = dict()
		cheek_style_sample = CheekStyleSample.objects.filter(
			id=sample_id, cheek_style_id=cheek_style_id
		).first()
		if cheek_style_sample:
			if cheek_style_sample.discern_status == 0:
				return gold_percent_value
			face_gold_values = FaceGoldValue.objects.filter(cheek_style_sample_id=sample_id)
			gpd_id2percent_value = {
				fgv.gold_percent_define_id: fgv.percent_value for fgv in face_gold_values
			}
			gold_percent_defines = GoldPercentDefine.objects.filter(is_online=1)
			gpd_id2gpd_obj = {gpd.id: gpd for gpd in gold_percent_defines}
			gold_percent_value["cheek_style_sample_name"] = u"样本%d" % cheek_style_sample.id
			gold_percent_value["cheek_style_sample_image_url"] = cheek_style_sample.image_url
			for gpd_id, gpd_obj in gpd_id2gpd_obj.items():
				percent_value = gpd_id2percent_value.get(gpd_id, 0)
				gold_percent_value[str(gpd_obj.id)] = round(percent_value, 2)
			return gold_percent_value

	def delete_cheek_style_sample(self, cheek_style_id, sample_id):
		cheek_style_sample = CheekStyleSample.objects.filter(
			id=sample_id, cheek_style_id=cheek_style_id
		).first()
		if cheek_style_sample:
			cheek_style_sample.deleted = 1
			cheek_style_sample.save()

	def update_cheek_style_sample_gold_value(self, sample_id, gold_values):
		cheek_style_sample = CheekStyleSample.objects.filter(
			id=sample_id, deleted=0, is_sample=1
		).first()
		if cheek_style_sample:
			face_gold_values = FaceGoldValue.objects.filter(
				cheek_style_sample_id=cheek_style_sample.id
			)
			gpd_id2face_gold_value = {
				fgv.gold_percent_define_id: fgv for fgv in face_gold_values
			}
			for gold_value in gold_values:
				face_gold_value = gpd_id2face_gold_value.get(gold_value["gold_percent_define_id"])
				if not face_gold_value:
					face_gold_value = FaceGoldValue()
				face_gold_value.cheek_style_sample_id = cheek_style_sample.id
				face_gold_value.gold_percent_define_id = gold_value["gold_percent_define_id"]
				face_gold_value.percent_value = gold_value["percent_value"]
				face_gold_value.save()
			# 已经调用旷视接口结算过美学值
			cheek_style_sample.discern_status = 1
			cheek_style_sample.save()
		return sample_id


class FeatureWeightValueService:

	def __init__(self):
		pass

	def query_feature_weight_values(self):
		feature_weight_values = FeatureWeightValue.objects.filter()
		result = []
		for feature_weight_value in feature_weight_values:
			fwv = dict()
			fwv["id"] = feature_weight_value.id
			fwv["secondary_demand_name"] = feature_weight_value.secondary_demand_name
			fwv["secondary_demand_id"] = feature_weight_value.secondary_demand_id
			fwv["unit"] = feature_weight_value.unit
			fwv["x_value"] = feature_weight_value.x_value
			fwv["y_value"] = feature_weight_value.y_value
			fwv["weight"] = feature_weight_value.weight
			fwv["tag_ids"] = feature_weight_value.tag_ids
			result.append(fwv)
		return result
