import json
import logging
import re
import numpy as np
from copyright.models import CopyrightBrief, CopyrightDetails, CopyrightCategoryConfig, CopyrightEntity, \
    CopyrightDraftBrief, CopyrightDraftDetails
from copyright.models import ProductItem
from copyright.enum import get_choice_key, get_choice_value
from partner.models import Company, Tag
from utils.exception import ValidateError
from .details_domain import DetailsService
from .category_domain import CategoryConfigService

logger = logging.getLogger('refresh_entity')
sys_logger = logging.getLogger('syslog')


class ImportService(object):
    PRODUCT_ID = 0
    brief_execl_chinese = ['产品ID', '版权文件名称', '授权链是否完整', '状态标签', '节目负责人', '签署公司', '介质是否有龙标']
    brief_execl_key = [0, 1, 2, 3, 4, 5, 6]

    draft_brief_execl_chinese = ['唯一ID', '媒资节ID', '版权文件名称', '上游版权方', '授权链是否完整', '状态标签', '授权开始时间',
                                 '授权结束时间', '授权区域ID', '节目负责人', '签署公司', '介质是否有龙标', '评级', '清晰度']
    draft_brief_execl_key = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15]

    detail_execl_chinese = ['产品ID/唯一ID', '黑白名单类型', '实体类型', '实体名称', '音频权', '视频权', '授权方式', '终端', '转授权',
                            '下载权', 'vip付费', '维权', '剪辑权', '附加权']
    detail_execl_key = [0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 16]

    @staticmethod
    def import_copyright_execl(brief_execl_datas, details_execl_datas, uid):
        ImportService.validate_copyriht_execl(brief_execl_datas, details_execl_datas)

        for brief_execl_data in brief_execl_datas:
            new_brief = ImportService.general_brief_data(brief_execl_data, uid)

            detail_product_execl_datas = details_execl_datas[details_execl_datas[:, 0] == brief_execl_data[0]]
            new_details_group = ImportService.general_import_copyright_details(
                detail_product_execl_datas, new_brief.id, uid, CopyrightDetails)

            CopyrightDetails.objects.bulk_create(new_details_group)

    @staticmethod
    def import_draft_copyright_execl(draft_brief_execl_datas, draft_details_execl_datas, uid):
        ImportService.validate_copyriht_draft_execl(draft_brief_execl_datas, draft_details_execl_datas)

        for draft_brief_execl_data in draft_brief_execl_datas:
            new_draft_brief = ImportService.general_draft_brief_data(draft_brief_execl_data, uid)

            draft_details_product_execl_datas = \
                draft_details_execl_datas[draft_details_execl_datas[:, 0] == draft_brief_execl_data[0]]
            new_draft_details_group = ImportService.general_import_copyright_details(
                draft_details_product_execl_datas, new_draft_brief.id, uid, CopyrightDraftDetails)

            CopyrightDraftDetails.objects.bulk_create(new_draft_details_group)

    @staticmethod
    def validate_copyriht_execl(brief_execl_datas, details_execl_datas):
        ImportService.validate_copyright_brief(brief_execl_datas)
        ImportService.validate_import_details(details_execl_datas)

    @staticmethod
    def validate_copyright_brief(brief_execl_datas):
        ImportService.validate_required(brief_execl_datas, ImportService.brief_execl_key,
                                        ImportService.brief_execl_chinese)

        if len(set(brief_execl_datas[:, 0])) != len(brief_execl_datas[:, 0]) or \
                CopyrightBrief.objects.filter(product_id__in=brief_execl_datas[:, 0]).exists():
            raise ValidateError('版权基本信息表 产品ID是唯一的，不可重复 请检查!')

    @staticmethod
    def validate_required(execl_datas, validate_key, validate_columns):
        for execl_data in execl_datas:
            for line_execl in validate_key:
                if execl_data[line_execl] == '':
                    raise ValidateError(validate_columns[line_execl] + ' 必填!')

    @staticmethod
    def validate_copyriht_draft_execl(draft_brief_execl_datas, draft_details_execl_datas):
        ImportService.validate_import_draft_brief(draft_brief_execl_datas)
        ImportService.validate_import_details(draft_details_execl_datas)

    @staticmethod
    def validate_import_draft_brief(draft_brief_execl_datas):
        ImportService.validate_required(draft_brief_execl_datas, ImportService.draft_brief_execl_key,
                                        ImportService.draft_brief_execl_chinese)

        if len(set(draft_brief_execl_datas[:, 0])) != len(draft_brief_execl_datas[:, 0]):
            raise ValidateError('版权基本信息表 唯一ID 不能重复 请检查!')

        ImportService.validate_up_company(draft_brief_execl_datas[:, 3])

    @staticmethod
    def validate_up_company(upstream_company_name_list):
        upstream_company_name_list = list(set('，'.join(upstream_company_name_list).split('，')))  # 实体合并去重
        sys_terminal = Company.objects.filter(title__in=upstream_company_name_list).exclude(category='Customer'). \
            values_list('title', flat=True)
        if len(upstream_company_name_list) != len(list(sys_terminal)):
            not_exist_entities = list(set(upstream_company_name_list).difference(set(list(sys_terminal))))
            raise ValidateError('上游版权方：' + ','.join(not_exist_entities) + ' not exist！')

    @staticmethod
    def validate_import_details(details_execl_datas):
        ImportService.validate_required(details_execl_datas, ImportService.detail_execl_key,
                                        ImportService.detail_execl_chinese)

        ImportService.validate_details_entity(details_execl_datas)
        ImportService.validate_details_terminals(details_execl_datas[:, 7])
        ImportService.validate_details_editing_program(details_execl_datas[:, 14])
        ImportService.validate_details_extra(details_execl_datas[:, 16])

    @staticmethod
    def validate_details_entity(details_execl_datas):
        for details_execl_data in details_execl_datas:
            product_black_group = details_execl_datas[(details_execl_datas[:, 0] == details_execl_data[0]) &
                                                      (details_execl_datas[:, 2] == details_execl_data[2])][:, 1]
            if details_execl_data[3][-1] == '，':
                raise ValidateError('实体不能以逗号结尾！请检查')

            if product_black_group[product_black_group == '黑名单'].size > 1:
                raise ValidateError('productId/唯一ID ' + str(details_execl_data[0]) + ' 黑名单只能设置一次！')

            product_black_group = list(set('，'.join(product_black_group).split('，')))  # 去重
            if len(product_black_group) > 1:
                raise ValidateError('productId/唯一ID ' + str(details_execl_data[0]) + ' 黑白名单类型只能选择一个！')

            ImportService.check_entity_is_exist(details_execl_data[3], details_execl_data[2])

    @staticmethod
    def check_entity_is_exist(entity_name, category_name):
        if entity_name != '全部':
            entity_name_list = entity_name.split('，')
            sys_entity = CopyrightEntity.objects.filter(name__in=entity_name_list). \
                filter(category__name=category_name).values_list('name', flat=True)
            if len(entity_name_list) != len(list(sys_entity)):
                not_exist_entitys = list(set(entity_name_list).difference(set(list(sys_entity))))
                raise ValidateError('实体: ' + ','.join(not_exist_entitys) + ' not exist！')

    @staticmethod
    def validate_details_terminals(terminals):
        if ImportService.validate_comma_ending(terminals):
            raise ValidateError('终端 不能以逗号结尾！请检查')
        if '' in terminals:
            raise ValidateError('终端 不能为空！请检查')

        terminal_name_list = list(set('，'.join(terminals).split('，')))  # 实体合并去重
        sys_terminal = CopyrightCategoryConfig.objects.filter(name__in=terminal_name_list). \
            filter(type=3).values_list('name', flat=True)

        if len(terminal_name_list) != len(list(sys_terminal)):
            not_exist_entitys = list(set(terminal_name_list).difference(set(list(sys_terminal))))
            raise ValidateError('终端: ' + ','.join(not_exist_entitys) + ' not exist！')

    @staticmethod
    def validate_details_editing_program(editing_program):
        if ImportService.validate_comma_ending(editing_program):
            raise ValidateError('编辑权 不能以逗号结尾！请检查')
        if '' in editing_program:
            raise ValidateError('编辑权 不能为空！请检查')
        editing_program_name_list = list(set('，'.join(editing_program).split('，')))  # 实体合并去重
        sys_editing_program = np.array(CopyrightDetails.EDITING_CHOICE)[:, 1]
        editing_not_in_sys = [item for item in editing_program_name_list if item not in sys_editing_program]
        if editing_not_in_sys:
            raise ValidateError('编辑权: ' + ','.join(editing_not_in_sys) + ' not exist！')

    @staticmethod
    def validate_details_extra(extra):
        if ImportService.validate_comma_ending(extra):
            raise ValidateError('附加权 不能以逗号结尾！请检查')
        if '' in extra:
            raise ValidateError('附加权 不能为空！请检查')
        extra_name_list = list(set('，'.join(extra).split('，')))  # 实体合并去重
        sys_extra = np.array(CopyrightDetails.EXTRA_CHOICE)[:, 1]
        extra_not_in_sys = [item for item in extra_name_list if item not in sys_extra]
        if extra_not_in_sys:
            raise ValidateError('附加权: ' + ','.join(extra_not_in_sys) + ' not exist！')

    @staticmethod
    def validate_comma_ending(validate_datas):
        for validate_data in validate_datas:
            if validate_data and validate_data[-1] == '，':
                return True
        return False

    @staticmethod
    def general_import_copyright_details(detail_execl_datas, copyright_id, uid, models):
        detail_insert_datas = []
        for detail in detail_execl_datas:
            detail_insert_datas.append(ImportService.general_copyright_details_data(detail, copyright_id, uid, models))
        return detail_insert_datas

    @staticmethod
    def general_brief_data(brief_execl_data, uid):
        return CopyrightBrief.objects.create(**{
            'media_id': ProductItem.objects.get(id=brief_execl_data[0]).media_id,
            'product_id': brief_execl_data[0],
            'document_name': brief_execl_data[1],
            'copyright_chain': 4 if brief_execl_data[2] == '' else
            get_choice_key(CopyrightBrief.CHAIN_CHOICE, brief_execl_data[2])[0],
            'status_label': {CopyrightBrief.get_status_label_key(brief_execl_data[3]): brief_execl_data[3]},
            'program_owner': brief_execl_data[4],
            'buyer_company': 5 if brief_execl_data[5] == '' else get_choice_key(CopyrightBrief.BUYER_COMPANY_CHOICE,
                                                                                brief_execl_data[5])[0],
            'film_release_licence': 2 if brief_execl_data[6] == '' else
            get_choice_key(CopyrightBrief.FILM_RELEASE_LICENCE_CHOICE,
                           brief_execl_data[6])[0],
            'remark': brief_execl_data[7],
            'user_id': uid})

    @staticmethod
    def general_draft_brief_data(draft_brief_execl_data, uid):
        partner = Company.objects.filter(title=draft_brief_execl_data[3]).values('id')
        return CopyrightDraftBrief.objects.create(**{
            'media_id': draft_brief_execl_data[1],
            'document_name': draft_brief_execl_data[2],
            'partner_id': list(partner)[0]['id'] if partner.exists() else None,
            'copyright_chain': 4 if draft_brief_execl_data[4] == '' else
            get_choice_key(CopyrightBrief.CHAIN_CHOICE, draft_brief_execl_data[4])[0],
            'status_label': {CopyrightBrief.get_status_label_key(draft_brief_execl_data[5]): draft_brief_execl_data[5]},
            'authorize_start_at': draft_brief_execl_data[6],
            'authorize_end_at': draft_brief_execl_data[7],
            'authorized_area_id': draft_brief_execl_data[8],
            'program_owner': draft_brief_execl_data[9],
            'buyer_company': CopyrightBrief.get_buyer_company_key(draft_brief_execl_data[10]),
            'film_release_licence': 2 if draft_brief_execl_data[11] == '' else
            get_choice_key(CopyrightBrief.FILM_RELEASE_LICENCE_CHOICE,
                           draft_brief_execl_data[11])[0],
            'episodes': draft_brief_execl_data[12] if draft_brief_execl_data[12] else None,
            'real_episodes': draft_brief_execl_data[13] if draft_brief_execl_data[13] else None,
            'item_level': get_choice_key(CopyrightBrief.ITEM_LEVEL_CHOICE, draft_brief_execl_data[14])[0],
            'definition': get_choice_key(CopyrightBrief.DEFINITION_CHOICE, draft_brief_execl_data[15])[0],
            'remark': draft_brief_execl_data[16],
            'user_id': uid})

    @staticmethod
    def general_copyright_details_data(detail_execl_data, copyright_id, uid, models):
        entity_category_id = CategoryConfigService.get_by_name_type(detail_execl_data[2], 2).id
        copyright_detail = {
            'copyright_id': copyright_id,
            'is_white': 1 if detail_execl_data[1] == '白名单' else 0,
            'entity_category_id': entity_category_id,
            'entity_ids': ImportService.entity_to_json(str(detail_execl_data[3]), entity_category_id),
            'white_entity_ids': ImportService.entity_to_json(str(detail_execl_data[3]), entity_category_id),
            'is_audio': get_choice_key(CopyrightDetails.AUDIO_CHOICE, detail_execl_data[4])[0],
            'is_video': get_choice_key(CopyrightDetails.VIDEO_CHOICE, detail_execl_data[5])[0],
            'authorized_way': get_choice_key(CopyrightDetails.AUTHORIZED_WAY_CHOICE, detail_execl_data[6])[0],
            'terminals': ImportService.terminal_to_json(detail_execl_data[7]),
            'with_granted': get_choice_key(CopyrightDetails.GRANTED_CHOICE, detail_execl_data[8])[0],
            'granted_area': detail_execl_data[9],
            'buffer_period': detail_execl_data[10] if detail_execl_data[10] else None,
            'is_download': get_choice_key(CopyrightDetails.DOWNLOAD_CHOICE, detail_execl_data[11])[0],
            'vip_pay': get_choice_key(CopyrightDetails.VIP_CHOICE, detail_execl_data[12])[0],
            'is_safeguard': get_choice_key(CopyrightDetails.SAFEGUARD_CHOICE, detail_execl_data[13])[0],
            'editing_program': ImportService.editing_program_to_json(detail_execl_data[14]),
            'editing_remark': detail_execl_data[15],
            'extra': ImportService.extra_to_json(detail_execl_data[16]),
            'user_id': uid,
            'status': 1}
        if copyright_detail['is_white']:
            copyright_detail['white_entity_ids'] = copyright_detail['entity_ids']
        else:
            copyright_detail['white_entity_ids'] = DetailsService.black_to_white(copyright_detail['entity_category_id'],
                                                                                 copyright_detail['entity_ids'])
        return models(**copyright_detail)

    @staticmethod
    def entity_to_json(entity_name, entity_category_id):
        if entity_name == '全部':
            return {'1': '全部'}
        elif entity_name == '':
            return {}
        else:
            names = entity_name.split('，')
            entities = CopyrightEntity.objects.filter(category_id=entity_category_id).filter(name__in=names).values(
                'id', 'name')
            return {entity['id']: entity['name'] for entity in entities}

    @staticmethod
    def terminal_to_json(terminal_name):
        if terminal_name == '':
            return {}
        terminal_names = terminal_name.split('，')
        terminals = CategoryConfigService.get_in_name(terminal_names, 3)
        return {terminal['id']: terminal['name'] for terminal in terminals}

    @staticmethod
    def editing_program_to_json(editing_program_name):
        editing_program_names = editing_program_name.split('，')
        editting_to_json = {}
        for editing_program in editing_program_names:
            editting_to_json[CopyrightDetails.get_editting_key(editing_program)] = editing_program
        return editting_to_json

    @staticmethod
    def extra_to_json(extra_name):
        extra_names = extra_name.split('，')
        extra_to_json = {}
        for extra_name in extra_names:
            extra_to_json[CopyrightDetails.get_extra_key(extra_name)] = extra_name
        return extra_to_json
