# -*- coding: UTF-8 -*-

from hippo.models.merchant import Merchant, MerchantRelevance, MerchantNonsync
from rpc.tool.log_tool import merchant_logger


class MerchantProxy(object):
    _model = Merchant

    def __init__(self, instance, *args, **kwargs):
        self._obj = instance

    def doctors_of_merchant(self):
        # 商户下的医生
        return [rel.doctor for rel in self._obj.merchant_doctors.all()]

    def doctors_of_officer(self):
        # 机构下的医生
        mch_doctor = self._obj.doctor
        return mch_doctor.merchant_doctors()

    def add_rel_doctors(self, doctors):
        ids = [d.id for d in doctors]
        # 存在关系的，更新商户
        exist_rels = MerchantRelevance.objects.filter(doctor_id__in=ids)
        exist_rels.update(merchant=self._obj)
        # 不存在的，添加记录
        not_exists_ids = set(ids) - set([r.doctor_id for r in exist_rels])
        MerchantRelevance.objects.bulk_create([
            MerchantRelevance(merchant=self._obj, doctor_id=did)
            for did in not_exists_ids
        ])

    def del_rel_doctors(self, doctors):
        doctor_ids = [d.id for d in doctors]
        merchant_logger.info(u'[%s - %s](%s)' % (self._obj.id, self._obj.doctor_id, u','.join(doctor_ids)))
        MerchantRelevance.objects.filter(
            merchant=self._obj,
            doctor_id__in=doctor_ids,
        ).delete()

    def update_merchant_info_by_doctor(self):
        # 通过商户医生更新商户信息
        fields = {
            'name': self._obj.doctor.name,
            'is_online': self._obj.doctor.is_merchant,
        }
        for f in fields:
            setattr(self._obj, f, fields[f])
        self._obj.save(update_fields=fields.keys())

    def update_relations_by_doctor(self):
        # 通过商户医生更新商户下的医生关系
        new_mch_doctors = self.doctors_of_officer()
        old_mch_doctors = self.doctors_of_merchant()
        add_doctors = set(new_mch_doctors) - set(old_mch_doctors)
        del_doctors = set(old_mch_doctors) - set(new_mch_doctors)
        self.add_rel_doctors(add_doctors)
        self.del_rel_doctors(del_doctors)

    def offline(self):
        # 商户下线
        if self._obj.is_online:
            self._obj.is_online = False
            self._obj.save()

    def can_sync(self):
        nosync_query = MerchantNonsync.objects.filter(merchant_id=self._obj.id)
        return not nosync_query.exists()

    @classmethod
    def is_merchant(cls, doctor):
        # 是否商户, Doctor.is_merchant
        return doctor.is_merchant

    @classmethod
    def doctor_of_merchant_map(cls, doctor_ids):
        """根据医生id获取对应的商户
        """
        rels = MerchantRelevance.objects.filter(doctor_id__in=doctor_ids).select_related('merchant')
        return {rel.doctor_id: rel.merchant for rel in rels}

    @classmethod
    def get_by_doctor_rel(cls, doctor):
        # 获取该医生所属的商户
        try:
            rel = MerchantRelevance.objects.get(doctor_id=doctor.id)
            return cls(rel.merchant)
        except:
            return None

    @classmethod
    def get_by_doctor_officer(cls, doctor):
        # 获取该医生的机构管理者对应的商户
        if doctor.is_merchant:
            return cls.get_by_doctor(doctor)
        mch_doctor = doctor.get_officer()
        # if mch_doctor and cls.is_merchant(mch_doctor):
        #     merchant, created = cls.upsert_by_doctor(mch_doctor)
        #     return merchant
        if mch_doctor:
            return cls.get_by_doctor(mch_doctor)
        return None

    @classmethod
    def get_by_doctor(cls, doctor):
        q = cls._model.objects.filter(doctor_id=doctor.id)
        try:
            return cls(q[0])
        except:
            return None

    @classmethod
    def create_by_doctor(cls, doctor):
        if not doctor:
            return None
        obj = cls._model(doctor=doctor)
        obj.save()
        return cls(obj)

    @classmethod
    def create_by_doctor_rel(cls, doctor):
        mch_doctor = doctor.get_officer()
        return cls.create_by_doctor(mch_doctor)

    @classmethod
    def upsert_by_doctor(cls, doctor, update_relation=False):
        # 根据doctor 创建或更新商户信息
        created = False
        if not cls.is_merchant(doctor):
            return None, created
        mch = cls.get_by_doctor(doctor)
        if not mch:
            mch = cls.create_by_doctor(doctor)
            created = True
        mch.update_merchant_info_by_doctor()
        if update_relation:
            mch.update_relations_by_doctor()
        return mch, created


def update_merchant_doctor_relation(doctor):
    # 判断所属商户是否可以进行同步
    mch = MerchantProxy.get_by_doctor_rel(doctor)
    # if mch and not mch.can_sync():
    #     print u'%s no need sync' % (mch._obj.id)
    #     return

    if MerchantProxy.is_merchant(doctor):
        # 判断doctor 是否是商户
        merchant, created = MerchantProxy.upsert_by_doctor(doctor, update_relation=True)
    else:
        # 不是商户
        mch = MerchantProxy.get_by_doctor(doctor)
        if mch:
            mch.offline()
        if not doctor.allow_hospital_agent:
            # 医生没有托管
            return
        # 获取新的商户
        new_merchant = MerchantProxy.get_by_doctor_officer(doctor)
        if new_merchant is None:
            new_merchant = MerchantProxy.create_by_doctor_rel(doctor)
        # 获取老的商户
        old_merchant = MerchantProxy.get_by_doctor_rel(doctor)

        if new_merchant is None and old_merchant is None:
            return
        if new_merchant is None:
            # 没有新商户，去掉老的关联
            old_merchant.del_rel_doctors([doctor])
        elif old_merchant is None:
            # 没有老商户，加入新的关联
            new_merchant.add_rel_doctors([doctor])
        elif new_merchant != old_merchant:
            # 去掉老的商户关系，添加新的商户关系
            new_merchant.add_rel_doctors([doctor])


def doctor_merchant_map(doctor_ids):
    doc_mch_map = MerchantProxy.doctor_of_merchant_map(doctor_ids)
    ret = {
        doc_id: getattr(doc_mch_map.get(doc_id, None), 'doctor_id', doc_id)
        for doc_id in doctor_ids
    }
    return ret
