import logging
import math
import os
import random

import requests
import xml.etree.ElementTree as ET
from domain.imdb.value_object import CelebrityRoleValue
from domain.lsp.generated.common_xsd import Adi
from domain.lsp.value_object import CodeFactory, C2ApiUtil
from imdb.models import CelebrityMediaRelationModel
from injector.models import MediaInfoSyncModel, TaskModel
from .base_injector import LspInjectorC2
from domain.injector.value_object import TaskStatusValue, DefinitionValue, ContentTypeValue

from utils.date_utils import datetime_now
import re

logger = logging.getLogger(__file__)


# 定义 广西移动的 id、 code 模式
class CodeFactory:
    Series = "00000010"
    Program = "00000001"
    Movie = "00000002"
    Picture = "00000008"
    Cast = "00000009"
    CastRoleMap = "16"
    Package = "00000011"
    Channel = "18"
    PhysicalChannel = "19"
    Schedule = "20"
    MOVIE = ""
    TV = ""

    def __init__(self, csp_code=""):
        self.csp_code = csp_code

    def gen_series_code(self, series_id):
        flag_0 = (32 - len(str(series_id)) - len(self.Series) - len(self.csp_code)) * "0"
        return "{}{}{}{}".format(self.csp_code, self.Series, flag_0, series_id)

    def gen_program_code(self, program_id):
        flag_0 = (32 - len(str(program_id)) - len(self.Program) - len(self.csp_code)) * "0"
        return "{}{}{}{}".format(self.csp_code, self.Program, flag_0, program_id)

    def gen_movie_code(self, movie_id):
        flag_0 = (32 - len(str(movie_id)) - len(self.Movie) - len(self.csp_code)) * "0"
        return "{}{}{}{}".format(self.csp_code, self.Movie, flag_0, movie_id)

    def gen_picture_code_0(self, media_id):
        s_media_id = str(media_id) + "0"
        flag_0 = (32 - len(s_media_id) - len(self.Picture) - len(self.csp_code)) * "0"
        return "{}{}{}{}".format(self.csp_code, self.Picture, flag_0, s_media_id)

    def gen_picture_code_1(self, media_id):
        s_media_id = str(media_id) + "1"
        flag_0 = (32 - len(s_media_id) - len(self.Picture) - len(self.csp_code)) * "0"
        return "{}{}{}{}".format(self.csp_code, self.Picture, flag_0, s_media_id)

    def gen_picture_code_2(self, media_id):
        s_media_id = str(media_id) + "2"
        flag_0 = (32 - len(s_media_id) - len(self.Picture) - len(self.csp_code)) * "0"
        return "{}{}{}{}".format(self.csp_code, self.Picture, flag_0, s_media_id)

    def gen_package_code(self):
        s_media_id = "20260331"
        flag_0 = (32 - len(s_media_id) - len(self.Package) - len(self.csp_code)) * "0"
        return "{}{}{}{}".format(self.csp_code, self.Package, flag_0, s_media_id)


# 定义广西移动注入类
class NeiMengYdIpTv(LspInjectorC2):

    def __init__(self, alias="NEIMENGYDIPTV"):
        super().__init__(alias)
        self.lsp_id = self.conf.lsp_id
        self.csp_id = self.conf.csp_id
        self.cms_api = self.conf.cms_api
        self.csp_name = self.conf.csp_name
        self.cast_sep = "|"
        self.region_sep = "|"
        self.genre_sep = "|"
        self.tag_sep = ","
        self.prefix_ID = "shhenmyd"
        self.parent_category = "shhenmyd000000098600000803270116"
        self.category_map = {"movie": "shhenmyd000000098600000803270200",
                             "tvseries": "shhenmyd000000098600000803270300",
                             "children": "shhenmyd000000098600000803270400",
                             "animation": "shhenmyd000000098600000803270500",
                             "variety": "shhenmyd000000098600000803270600"}
        self.package_map = {1: {"name": "内蒙古移动视禾收费内容包", "code": "shhenmyd000000118600000806260200"},
                            0: {"name": "内蒙古移动视禾免费内容包", "code": "shhenmyd000000118600000806260201"}}
        self.code_factory = CodeFactory(self.prefix_ID)
        self.csp_name = "宁波视禾"
        self.desc_prefix = ""
        self.FTP_HOST = "172.25.129.68"
        self.HOST = "172.25.129.68"

        self.Category_TAG_MAP = {
            "movie": {'全部': '01', '喜剧': '02', '纪录': '03', '武侠': '04', '历史': '05', '恐怖': '06',
                      '奇幻': '07', '战争': '08', '冒险': '09', '爱情': '10', '伦理': '11', '动作': '12',
                      '运动': '13', '犯罪': '14', '音乐': '15', '惊悚': '16', '歌舞': '17', '科幻': '18',
                      '网络电影': '19', '悬疑': '20', '动画': '21', '警匪': '22', '家庭': '23', '剧情': '24',
                      '传记': '25'},
            "tvseries": {'全部': '01', '古装': '02', '悬疑': '03', '历史': '04', '都市': '05', '武侠': '06',
                         '喜剧': '07', '玄幻': '08', '农村': '09', '穿越': '10', '家庭': '11', '科幻': '12',
                         '剧情': '13', '校园': '14', '网剧': '15', '偶像': '16', '谍战': '17', '青春': '18',
                         '罪案': '19', '言情': '20', '年代': '21', '军旅': '22', '战争': '23', '其他': '24'},
            "children": {'全部': '01', '儿歌': '02', '英语': '03', '玩具': '04', '国学': '05', '手工': '06',
                         '友情': '07', '合家欢': '08', '战斗': '09', '绘本': '10', '科幻': '11', '男孩': '12',
                         '热血': '13', '女孩': '14', '魔法': '15', '真人': '16', '艺术': '17', '亲子': '18',
                         '科普': '19', '早教': '20', '益智': '21', '冒险': '22', '搞笑': '23', '其他': '24'},
            "animation": {'全部': '01', '国漫': '02', '励志': '03', '日漫': '04', '剧情': '05', '搞笑': '06',
                          '竞技': '07', '热血': '08', '武侠': '09', '战斗': '10', '治愈': '11', '冒险': '12',
                          '其他': '21', '校园': '14', '青春': '15', '恋爱': '16', '科幻': '17', '历史': '18',
                          '推理': '19', '奇幻': '20'},
            "variety": {'全部': '01', '相声': '02', '情感': '03', '亲子': '04', '晚会': '05', '真人秀': '06',
                        '脱口秀': '07', '音乐': '08', '文化': '09', '舞蹈': '10', '职场': '11', '游戏': '12',
                        '访谈': '13', '美食': '14', '生活': '15', '时尚': '16', '旅游': '17', '偶像': '18',
                        '明星': '19', '其他': '20'}
        }

    def get_stbld_nums(self):
        the_num = TaskModel.objects.filter(partner_id=self.lsp_pk).count()
        if len(str(the_num)) <= 5:
            return str(the_num).rjust(5, "0")
        elif len(str(the_num)) <= 7:
            return str(the_num).rjust(7, "0")
        else:
            return "{}{}".format(random.randint(10, 99), str(the_num)[-5:])

    def get_content_type(self, content_type):
        return {
            ContentTypeValue.POSITIVE: "正片",
            ContentTypeValue.CLIP: "花絮",
            ContentTypeValue.TRAILER: "预告片"
        }.get(content_type, "正片")

    # 清晰度（1:高清HD、2:流畅LD、3:标清SD、4：XD，默认SD）
    def _get_bit_rate_type(self, definition):
        if definition == DefinitionValue.P320:
            return "LD"
        elif definition == DefinitionValue.P480:
            return "SD"
        elif definition == DefinitionValue.P720:
            return "HD"
        elif definition == DefinitionValue.P1080:
            return "XD"
        elif definition == DefinitionValue.K4:
            return "XD"
        return "SD"

    def _get_video_type(self, type):

        type_mapper = {"h264": "H.264", "hevc": "H.265", "mpeg4": "MPEG4", "mpeg2": "MPEG2", "avs": "AVS",
                       "avs2": "AVS2"}

        return type_mapper[type]

    def _get_audio_type(self, type):

        type_mapper = {"aac": "AAC", "mp2": "MP2"}

        return type_mapper[type]

    def _get_video_bit(self, bit_rate):
        # 码率 kbit/s  并保持 各位、十位是0
        speed = bit_rate / 1000
        speed1 = round(speed / 100) * 100
        return speed1

    def _get_audio_bit(self, bit_rate):
        # 码率 kbit/s  并保持各位、十位是0
        speed = bit_rate / 1000
        if speed < 150:
            return 128
        elif speed < 200:
            return 192
        else:
            return speed

    def _get_resolution(self, definition, width):
        def_mapper = {DefinitionValue.P720: "720P",
                      DefinitionValue.P1080: "1080i",
                      DefinitionValue.K4: "4096i(4K)" if width == 3840 else "3840i(4K)"}
        return def_mapper[definition]

    def get_tags(self, media_obj):
        genres = media_obj.genres
        if genres and len(genres):
            names = [genre["name"] for genre in genres]
            return self.tag_sep.join(names)
        return ""

    def wrap_cdata_text(self, text):
        return f"<![CDATA[{text}]]>"

    def property_series(self, ps_id, media, media_ext, action="REGIST"):
        _actors = CelebrityMediaRelationModel.objects.filter(
            media_id=media.id, role=CelebrityRoleValue.ACTOR).select_related("celebrity")[:4]
        _directors = CelebrityMediaRelationModel.objects.filter(
            media_id=media.id, role=CelebrityRoleValue.DIRECTOR).select_related("celebrity")[:4]
        _writers = CelebrityMediaRelationModel.objects.filter(
            media_id=media.id, role=CelebrityRoleValue.AUTHOR).select_related("celebrity")[:2]
        actors, directors, writers = self.join_names(_actors), self.join_names(_directors), self.join_names(
            _writers)

        search_name = self.transform_chinese_to_letter(media.name)

        vst, vet = self.get_media_effective_time(media.id)

        the_property = [
            {"Name": self.wrap_cdata_text(self.get_media_name_by_alias(media))},
            {"SearchName": search_name},
            {"ActorDisplay": actors},  #
            {"Kpeople": actors},
            {"Language": media.languages},
            {"ScriptWriter": writers},
            {"Director": directors},
            {"Description": self.wrap_cdata_text(self.make_desc_prefix(media.storyline))},
            {"ReleaseYear": media.year},
            {"VolumnCount": media.episodes},
            {"OrgAirDate": ""},
            {"OriginalCountry": self.get_regions(media)},
            {"SeriesType": 0},
            {"Duration": math.ceil(media.total_seconds / 60)},
            {"scriptWriter": writers},  # 这里要写编剧
            {"Recommendation": media_ext.focus},
            {"Status": 1},
            {"LicensingWindowStart": vst},
            {"LicensingWindowEnd": vet}
        ]
        return {
            "element_type": "Series",
            "id": ps_id,
            "code": ps_id,
            "action": action,
            "property": the_property
        }

    def to_picture_ftp_url(self, pic_url, size):
        file_path = re.split('/', pic_url, 3)[-1]
        # 判断图片是否存在，存在直接引用，不存在就创建
        file_path = self.zoom_picture(file_path, pic_url, size)
        storage_ftp_url = "ftp://{}:{}@{}:{}/{}".format("senyucp", "Yk_29833vf", self.FTP_HOST,
                                                        "2121", file_path)
        return storage_ftp_url

    def property_picture(self, _id, file_url, size, action="REGIST"):
        return {
            "element_type": "Picture",
            "id": _id,
            "code": _id,
            "action": action,
            "property": [
                {"FileURL": self.to_picture_ftp_url(file_url, size)},
            ]
        }

    def property_category(self, _id, name, action="REGIST"):
        return {
            "element_type": "Category",
            "id": _id,
            "code": _id,
            "parentcode": self.parent_category,
            "action": action,
            "property": [
                {"Name": name},
                {"Status": 1}
            ]
        }

    def property_third_category(self, _id, _pid, name, action="REGIST"):
        return {
            "element_type": "Category",
            "id": _id,
            "code": _id,
            "parentcode": _pid,
            "action": action,
            "property": [
                {"Name": name},
                {"Status": 1}
            ]
        }

    def property_parent_category(self, action="REGIST"):
        return {
            "element_type": "Category",
            "id": self.parent_category,
            "code": self.parent_category,
            "parentcode": 0,
            "action": action,
            "property": [
                {"Name": "内蒙古移动视禾"},
                {"Status": 1}
            ]
        }

    def property_package(self, _id, name, action="REGIST"):
        return {
            "element_type": "Package",
            "id": _id,
            "code": _id,
            "action": action,
            "property": [
                {"Name": name},
                {"Status": 1},
                {"type": 0},
            ]
        }

    # 广西移动，要求简介 有前缀
    def make_desc_prefix(self, content):
        return self.desc_prefix + content

    # 广西移动只支持一个国家 目前处理是取第一个国家
    def get_regions(self, media_obj):
        regions = media_obj.regions
        if regions and len(regions):
            names = [region["name"] for region in regions]
            # 目前个别平台 需要改成内地，先分开处理,平台统一后在 统一处理
            if names[0] == "中国大陆":
                return "内地"
            return names[0]
        return ""

    def property_human_mapping(self, p_type, e_type, pid, eid, sub_property, action="REGIST"):
        the_map = {
            "parent_type": p_type,
            "parent_id": pid,
            "element_type": e_type,
            "element_id": eid,
            "parent_code": pid,
            "element_code": eid,
            "action": action,
            "property": sub_property
        }
        return the_map

    # 解除包映射
    def unbind_package_mapping(self, media, action="DELETE"):

        param_dict = {"category": media.category, "is_charge": 1}
        change_fields = self.injected_change.get_injected_fields(media.id, self.lsp_pk, param_dict)

        ps_id = self.code_factory.gen_series_code(media.id)

        pk_id = self.package_map[change_fields["is_charge"]]["code"]
        pk_name = self.package_map[change_fields["is_charge"]]["name"]

        package_sub_property = [
            {"ElementName": self.wrap_cdata_text(self.get_media_name_by_alias(media))},
            {"ParentName": pk_name},
        ]
        package_series_mapping = self.property_human_mapping("Package", "Series", pk_id, ps_id, package_sub_property,
                                                             action=action)
        data = {
            "object_list": [],
            "mapping_list": [package_series_mapping]
        }

        xml = Adi.to_xml(data, flag="Nope")

        return xml

        # 定义剧头信息

    def unbind_category_mapping(self, media, action="DELETE"):
        tag_series_mapping_list = []

        # param_dict = {"category": media.category, "is_charge": 1}
        # change_fields = self.injected_change.get_injected_fields(media.id, self.lsp_pk, param_dict)
        category = "tvseries"

        # tags = self.get_genre(media)
        # tags = [tag for tag in tags.split(self.genre_sep)]
        tags = ["农村", "剧情", "校园", "青春"]

        for tag in tags:
            tag_sub_property = [
                {"ElementName": self.wrap_cdata_text(self.get_media_name_by_alias(media))},
                {"ParentName": tag},
            ]

            cate_pid = self.category_map[category]
            c_id = cate_pid[:-2] + self.Category_TAG_MAP[category][tag]
            ps_id = self.code_factory.gen_series_code(media.id)
            tag_series_mapping1 = self.property_human_mapping("Category", "Series", c_id, ps_id, tag_sub_property,
                                                              action=action)
            tag_series_mapping_list.append(tag_series_mapping1)

        tag_sub_property = [
            {"ElementName": self.wrap_cdata_text(self.get_media_name_by_alias(media))},
            {"ParentName": "电视剧"},
        ]
        c_id = cate_pid[:-2] + self.Category_TAG_MAP[category][tag]
        tag_series_mapping1 = self.property_human_mapping("Category", "Series", c_id, ps_id, tag_sub_property,
                                                          action=action)
        data = {
            "object_list": [],
            "mapping_list": [tag_series_mapping1] + tag_series_mapping_list
        }

        xml = Adi.to_xml(data, flag="Nope")

        return xml

    # def _album_series_header(self, media, media_ext, info_sync):
    #
    #     param_dict = {"category": media.category, "is_charge": 1}
    #     change_fields = self.injected_change.get_injected_fields(media.id, self.lsp_pk, param_dict)
    #     category_name = self._get_category_desc(change_fields["category"])
    #
    #     media_verpic = media_ext.media_verpic
    #     media_horpic = media_ext.media_horpic
    #     # 185x265
    #     size_verpic = self.image_resize.NEIMENGYDIPTV.get("verpic")
    #     # 255*193
    #     size_horpic = self.image_resize.NEIMENGYDIPTV.get("horpic")
    #
    #     size_verpic_0 = (255, 377)
    #
    #     # tags = self.get_genre(media)
    #     # tags = [tag for tag in tags.split(self.genre_sep)]
    #     tags = ["农村", "剧情"]
    #     # 定义ID、Action、Code
    #     action = info_sync.action_description()
    #     # 获取必要信息
    #     ps_id = self.code_factory.gen_series_code(media.id)
    #     p_series = self.property_series(ps_id, media, media_ext, action)
    #     pt_id_0 = self.code_factory.gen_picture_code_0(media.id)
    #     pt_id_1 = self.code_factory.gen_picture_code_1(media.id)
    #     pt_id_2 = self.code_factory.gen_picture_code_2(media.id)
    #
    #     pk_id = self.package_map[change_fields["is_charge"]]["code"]
    #     pk_name = self.package_map[change_fields["is_charge"]]["name"]
    #     p_picture_0 = self.property_picture(pt_id_0, media_verpic, size_verpic_0, action)
    #     p_picture_1 = self.property_picture(pt_id_1, media_verpic, size_verpic, action)
    #     p_picture_2 = self.property_picture(pt_id_2, media_horpic, size_horpic, action)
    #
    #     pc_id = self.category_map[change_fields["category"]]
    #
    #     # p_category = self.property_category(pc_id, category_name, action)
    #
    #     # p_package = self.property_package(pk_id, pk_name)
    #
    #     picture_0_series_mapping = self.property_mapping("Picture", "Series", pt_id_0, ps_id, 0, action=action)
    #     picture_1_series_mapping = self.property_mapping("Picture", "Series", pt_id_1, ps_id, 1, action=action)
    #     picture_2_series_mapping = self.property_mapping("Picture", "Series", pt_id_2, ps_id, 2, action=action)
    #     package_sub_property = [
    #         {"ElementName": self.wrap_cdata_text(self.get_media_name_by_alias(media))},
    #         {"ParentName": pk_name},
    #     ]
    #     package_series_mapping = self.property_human_mapping("Package", "Series", pk_id, ps_id, package_sub_property,
    #                                                          action=action)
    #     tag_series_mapping_list = []
    #     for tag in tags:
    #         tag_sub_property = [
    #             {"ElementName": self.wrap_cdata_text(self.get_media_name_by_alias(media))},
    #             {"ParentName": tag},
    #         ]
    #         cate_pid = self.category_map[change_fields["category"]]
    #         c_id = cate_pid[:-2] + self.Category_TAG_MAP[change_fields["category"]][tag]
    #         tag_series_mapping1 = self.property_human_mapping("Category", "Series", c_id, ps_id, tag_sub_property,
    #                                                           action=action)
    #         tag_series_mapping_list.append(tag_series_mapping1)
    #
    #     return {
    #         "object_list": [p_series, p_picture_0, p_picture_1, p_picture_2],
    #         "mapping_list": [picture_0_series_mapping, picture_1_series_mapping, picture_2_series_mapping,
    #                          package_series_mapping] + tag_series_mapping_list
    #     }

    # 定义剧头xml信息
    def album(self, _task_id, action="REGIST"):
        # 获取taskId
        task_id = str(_task_id).split("_")[0]
        # 从MediaInfo中获取media信息
        info_sync = MediaInfoSyncModel.objects.filter(pk=task_id).select_related("media").first()
        media = info_sync.media
        media_ext = media.mediaextfieldmodel
        data = self._album_series_header(media, media_ext, info_sync)
        logger.warning(data)
        xml = Adi.to_xml(data, flag="Nope")
        logger.warning(xml)
        return xml

    def get_storage_ftp_url(self, http_url):
        self.FTP_STORAGE_HOST = "112.16.171.210"
        file_path = re.split('/', http_url, 3)[-1]
        storage_ftp_url = "ftp://{}:{}@{}:{}/{}".format(
            self.FTP_STORAGE_USER, self.FTP_STORAGE_PASSWORD, self.FTP_STORAGE_HOST, self.FTP_STORAGE_PORT, file_path)
        return storage_ftp_url

    def gen_media_spec_info(self, storage):
        v_code = self._get_video_type(storage.v_codec)
        v_bit_rate = storage.bit_rate // 1000
        resolution = self._get_resolution(storage.definition, storage.width)
        frame_rate = storage.frame_rate
        a_code = self._get_audio_type(storage.a_codec)
        a_bit_rate = storage.a_bit_rate // 1000
        info = f"TS-VBR-{v_code}-{v_bit_rate}-{resolution}-{frame_rate}-{a_code}-{a_bit_rate}"
        return info

    def property_movie(self, _id, media_storage, _type=1, action="REGIST"):
        return {
            "element_type": "Movie",
            "id": _id,
            "code": _id,
            "action": action,
            "property": [
                {"Code": _id},
                {"FileURL": self.get_storage_ftp_url(media_storage.url)},
                {"MediaSpec": self.gen_media_spec_info(media_storage)},
                {"Type": 1},
            ]
        }

    def property_child_program(self, ppid, media, media_storage, episode, action="REGIST"):

        actors, directors, writers = self.get_media_person(media, actor=4, director=4, writer=2)
        vst, vet = self.get_media_effective_time(media.id)
        episode_title = self.get_episode_title(media, episode)

        p_program = {
            "element_type": "Program",
            "id": ppid,
            "code": ppid,
            "action": action,
            "property": [
                {"Code": ppid},
                {"Name": episode_title},
                {"ContentProvider": self.csp_name},
                {"ActorDisplay": directors},
                {"WriterDisplay": actors},
                {"scriptWriter": writers},
                {"Description": self.wrap_cdata_text(media.storyline)},
                {"Duration": math.ceil(media_storage.seconds / 60)},
                {"OriginalCountry": self.get_regions(media)},
                {'SeriesFlag': 1},
                {"SourceType": 1},
                {"Status": 1},
                {"LicensingWindowStart": vst},
                {"LicensingWindowEnd": vet}
            ]
        }
        return p_program

    def property_movie_program(self, ppid, media, media_storage, episode, media_ext, action="REGIST"):

        actors, directors, writers = self.get_media_person(media, actor=4, director=4, writer=2)

        search_name = self.transform_chinese_to_letter(media.name)

        vst, vet = self.get_media_effective_time(media.id)

        p_program = {
            "element_type": "Program",
            "id": ppid,
            "code": ppid,
            "action": action,
            "property": [
                {"Name": self.wrap_cdata_text(self.get_media_name_by_alias(media))},
                {"SearchName": search_name},
                {"ActorDisplay": actors},  #
                {"Kpeople": actors},
                {"Language": media.languages},
                {"ScriptWriter": writers},
                {"Director": directors},
                {"Description": self.wrap_cdata_text(self.make_desc_prefix(media.storyline))},
                {"ReleaseYear": media.year},
                {"OrgAirDate": ""},
                {"OriginalCountry": self.get_regions(media)},
                {"Duration": math.ceil(media.total_seconds / 60)},
                {"scriptWriter": writers},  # 这里要写编剧
                {"ContentProvider": self.csp_name},
                {"Recommendation": media_ext.focus},
                {"Status": 1},
                {"SourceType": 1},
                {"SeriesFlag": 0},
                {"LicensingWindowStart": vst},
                {"LicensingWindowEnd": vet}
            ]
        }
        return p_program

    # 定义分集信息
    def _album_sub_series(self, media_storage, media, episode, media_ext, _episodes, action="REGIST"):

        # 还需要添加媒资信息
        psid = self.code_factory.gen_series_code(media.id)
        ppid = self.code_factory.gen_program_code(media_storage.id)
        # 定义 program 对象部分
        p_program = self.property_child_program(ppid, media, media_storage, episode, action)
        # 定义 program 与movie的关系
        pmid = self.code_factory.gen_movie_code(media_storage.id)
        p_movie = self.property_movie(pmid, media_storage, action=action)

        mapping_program = self.property_mapping("Series", "Program", psid, ppid, sequence=episode.serial_num,
                                                action=action)

        mapping_movie = self.property_mapping("Program", "Movie", ppid, pmid, action=action)

        return {
            "object_list": [p_program, p_movie],
            "mapping_list": [mapping_program, mapping_movie]
        }

    # 定义电影
    def _album_movie(self, media_storage, media, episode, media_ext, action):

        param_dict = {"category": media.category, "is_charge": 1}
        change_fields = self.injected_change.get_injected_fields(media.id, self.lsp_pk, param_dict)

        media_verpic = media_ext.media_verpic
        media_horpic = media_ext.media_horpic
        # 185x265
        size_verpic = self.image_resize.NEIMENGYDIPTV.get("verpic")
        # 255*193
        size_horpic = self.image_resize.NEIMENGYDIPTV.get("horpic")

        size_verpic_0 = (255, 377)

        # tags = [tag for tag in tags.split(self.genre_sep)]
        tags = ["爱情", "剧情"]

        media_ext = media.mediaextfieldmodel

        ppid = self.code_factory.gen_program_code(media.id)
        p_program = self.property_movie_program(ppid, media, media_storage, episode, media_ext, action)

        pmid = self.code_factory.gen_movie_code(media_storage.id)
        p_movie = self.property_movie(pmid, media_storage, action=action)

        pt_id_0 = self.code_factory.gen_picture_code_0(media.id)
        pt_id_1 = self.code_factory.gen_picture_code_1(media.id)
        pt_id_2 = self.code_factory.gen_picture_code_2(media.id)

        p_picture_0 = self.property_picture(pt_id_0, media_verpic, size_verpic_0, action)
        p_picture_1 = self.property_picture(pt_id_1, media_verpic, size_verpic, action)
        p_picture_2 = self.property_picture(pt_id_2, media_horpic, size_horpic, action)

        pk_id = self.package_map[change_fields["is_charge"]]["code"]
        pk_name = self.package_map[change_fields["is_charge"]]["name"]

        mapping_movie = self.property_mapping("Program", "Movie", ppid, pmid, action=action)

        picture_0_series_mapping = self.property_mapping("Picture", "Program", pt_id_0, ppid, 0, action=action)
        picture_1_series_mapping = self.property_mapping("Picture", "Program", pt_id_1, ppid, 1, action=action)
        picture_2_series_mapping = self.property_mapping("Picture", "Program", pt_id_2, ppid, 2, action=action)

        package_sub_property = [
            {"ElementName": self.wrap_cdata_text(self.get_media_name_by_alias(media))},
            {"ParentName": pk_name},
        ]
        package_series_mapping = self.property_human_mapping("Package", "Program", pk_id, ppid, package_sub_property,
                                                             action=action)

        tag_series_mapping_list = []
        for tag in tags:
            tag_sub_property = [
                {"ElementName": self.wrap_cdata_text(self.get_media_name_by_alias(media))},
                {"ParentName": tag},
            ]
            cate_pid = self.category_map[change_fields["category"]]
            c_id = cate_pid[:-2] + self.Category_TAG_MAP[change_fields["category"]][tag]
            tag_series_mapping1 = self.property_human_mapping("Category", "Program", c_id, ppid, tag_sub_property,
                                                              action=action)
            tag_series_mapping_list.append(tag_series_mapping1)

        return {
            "object_list": [p_program, p_movie, p_picture_0, p_picture_1, p_picture_2],
            "mapping_list": [mapping_movie, picture_0_series_mapping, picture_1_series_mapping,
                             picture_2_series_mapping, package_series_mapping] + tag_series_mapping_list
        }

    # 定义节目xml信息
    def program(self, _task_id, action="REGIST"):
        task_id, _ = _task_id.split("_", 1)
        task = TaskModel.objects.filter(pk=task_id).select_related("storage").first()
        media_storage = task.storage  # 媒介
        media = media_storage.media  # 媒体文件主体
        episode = media_storage.episode  # (分集)扩展信息
        media_ext = media.mediaextfieldmodel  # 媒体文件补充信息

        # 目前的设计是 任何媒介都要有1集  电影也要设置为1集
        _episodes = int(media.episodes) if media.episodes else 0
        if _episodes > 1:  # 如果大于1 表示 连续剧 则该介质是某集电视剧
            data = self._album_sub_series(media_storage, media, episode, media_ext, _episodes, action)
        else:  # 电影
            data = self._album_movie(media_storage, media, episode, media_ext, action)
        xml = Adi.to_xml(data, flag="Nope")
        logger.warning(xml)
        return xml

    # 剧头注入  向LSP发起xml内容
    def exec_sync_header_cmd(self, sync, count=0):
        count += 1
        _sync_id = self.generate_correlate_id(sync.id, stage="series")
        cmd_file_url = self.get_cmd_ftp_url(self.csp_id, _sync_id)
        sync_id = "{}_{}".format(_sync_id, datetime_now())

        xml = C2ApiUtil.REQUESTXML.format(self.csp_id, self.lsp_id, sync_id, cmd_file_url)
        logger.warning("{} exec_sync_header_cmd HEADER_ID: {}, Request: {}".format(self.lsp_id, sync.id, xml))
        headers = {"content-type": "text/xml", "SOAPAction": "application/soap+xml;charset=utf8"}
        response = requests.post(self.cms_api, data=xml, headers=headers).content
        logger.warning("{} exec_sync_header_cmd HEADER_ID: {}, Response: {}".format(self.lsp_id, sync.id, response))
        tree = ET.fromstring(response)
        msg = tree.find(".//ErrorDescription").text
        if msg.lower() == "success":
            status = MediaInfoSyncModel.SYNCING
        else:
            if str(msg).lower().__contains__("could not connect") and count < self.try_count:
                return self.exec_sync_header_cmd(sync, count)
            status = MediaInfoSyncModel.FAILED
        the_sync = MediaInfoSyncModel.objects.filter(pk=sync.id)
        if the_sync.first().status == MediaInfoSyncModel.PENDING:
            the_sync.update(status=status)
        return

    def propery_category_obj(self, category_name, third_name, action):
        if third_name:
            pid = self.category_map[category_name]
            _id = pid[:-2] + self.Category_TAG_MAP[category_name][third_name]
            p_category = self.property_third_category(_id, pid, third_name, action)
        else:
            if category_name == "parent":
                p_category = self.property_parent_category(action)
            else:
                pc_id = self.category_map[category_name]
                name = self._get_category_desc_o(category_name)

                p_category = self.property_category(pc_id, name, action)
        return {
            "object_list": [p_category],
            "mapping_list": []
        }

    def peropery_package_obj(self, pk_id, pk_name, action="REGIST"):
        p_package = self.property_package(pk_id, pk_name, action)
        return {
            "object_list": [p_package],
            "mapping_list": []
        }

    def package_obj(self, pk_id, pk_name, action="REGIST"):
        data = self.peropery_package_obj(pk_id, pk_name, action)
        xml = Adi.to_xml(data, flag="Nope")
        logger.warning(xml)
        return xml

    def category_obj(self, category_name, third_name, action="REGIST"):
        # 获取taskId
        # category_name = "parent"
        # action = "DELETE"  movie tvseries children  animation variety
        # category_name = "movie"
        # third_name = "喜剧"
        data = self.propery_category_obj(category_name, third_name, action)
        xml = Adi.to_xml(data, flag="Nope")
        logger.warning(xml)
        return xml

    def bind_category_mapping(self, media, category_name, genre, action="REGIST"):
        # category_name = "tvseries"
        # tag = "穿越"
        tag = genre.name
        psid = self.code_factory.gen_series_code(media.id)
        pid = self.category_map[category_name]
        _id = pid[:-2] + self.Category_TAG_MAP[category_name][tag]
        tag_sub_property = [
            {"ElementName": self.wrap_cdata_text(self.get_media_name_by_alias(media))},
            {"ParentName": tag},
        ]
        tag_series_mapping1 = self.property_human_mapping("Category", "Series", _id, psid, tag_sub_property,
                                                          action=action)

        data = {
            "object_list": [],
            "mapping_list": [tag_series_mapping1]
        }
        xml = Adi.to_xml(data, flag="Nope")
        logger.warning(xml)
        return xml

    # 单独解绑分类
    # def series_header_injector(self, sync):
    #     header_id = self.generate_correlate_id(sync.id, stage="category")
    #     media = sync.media
    #     xml = self.unbind_category_mapping(media)
    #     logging.warning(xml)
    #     dir_path = self.get_xml_file_dir_path()
    #     if not os.path.exists(dir_path):
    #         os.makedirs(dir_path, exist_ok=True)
    #     file_path = self.get_xml_file_app_path(self.csp_id, header_id)
    #     with open(file_path, "w") as f:
    #         f.write(xml)
    #     self.exec_sync_header_cmd(sync)
    #     return

    # 单独添加分类
    def series_category_bind(self, sync, category_name, genre, action="REGIST"):

        header_id = self.generate_correlate_id(sync.id, stage="category")
        media = sync.media
        xml = self.bind_category_mapping(media, category_name, genre, action)
        logging.warning(xml)
        dir_path = self.get_xml_file_dir_path()
        if not os.path.exists(dir_path):
            os.makedirs(dir_path, exist_ok=True)
        file_path = self.get_xml_file_app_path(self.csp_id, header_id)
        with open(file_path, "w") as f:
            f.write(xml)
        self.exec_sync_header_cmd(sync)
        return

    # 单独解绑包
    # def series_header_injector(self, sync):
    #     header_id = self.generate_correlate_id(sync.id, stage="package")
    #     media = sync.media
    #     xml = self.unbind_package_mapping(media)
    #     logging.warning(xml)
    #     dir_path = self.get_xml_file_dir_path()
    #     if not os.path.exists(dir_path):
    #         os.makedirs(dir_path, exist_ok=True)
    #     file_path = self.get_xml_file_app_path(self.csp_id, header_id)
    #     with open(file_path, "w") as f:
    #         f.write(xml)
    #     self.exec_sync_header_cmd(sync)
    #     return

    # 单独注入两个包
    def series_package_injector(self, sync, name, code, action):
        header_id = self.generate_correlate_id(sync.id, stage="package")
        # name = "内蒙古移动视禾收费内容包"
        # code = "shhenmyd000000118600000806260200"
        # name = "内蒙古移动视禾免费内容包"
        # code = "shhenmyd000000118600000806260201"
        # action = "REGIST"
        xml = self.package_obj(code, name, action)
        dir_path = self.get_xml_file_dir_path()
        if not os.path.exists(dir_path):
            os.makedirs(dir_path, exist_ok=True)
        file_path = self.get_xml_file_app_path(self.csp_id, header_id)
        with open(file_path, "w") as f:
            f.write(xml)
        self.exec_sync_header_cmd(sync)
        return

    # 单独注入三级分类
    def series_category_injector(self, sync, category_name, third_name, action="REGIST"):
        header_id = self.generate_correlate_id(sync.id, stage="category")
        # category_name = "movie"
        # third_name = "喜剧"
        xml = self.category_obj(category_name, third_name, action)
        dir_path = self.get_xml_file_dir_path()
        if not os.path.exists(dir_path):
            os.makedirs(dir_path, exist_ok=True)

        file_path = self.get_xml_file_app_path(self.csp_id, header_id)
        with open(file_path, "w") as f:
            f.write(xml)
        self.exec_sync_header_cmd(sync)
        return

    # 剧头注入处理
    # def series_header_injector(self, sync):
    #     if sync.status == MediaInfoSyncModel.PENDING:
    #         header_id = self.generate_correlate_id(sync.id, stage="series")
    #         file_path = self.save_album_xml_file(self.csp_id, header_id, param="series")
    #         print("file_path", file_path)
    #         self.exec_sync_header_cmd(sync)
    #     return

    # 介质注入 向LSP发起xml内容
    def exec_cmd(self, task_id, count=0):
        count += 1
        _task_id = self.generate_correlate_id(task_id)
        cmdfileUrl = self.get_cmd_ftp_url(self.csp_id, _task_id)  # ftp协议
        xml = C2ApiUtil.REQUESTXML.format(self.csp_id, self.lsp_id, "{}_{}".format(_task_id, datetime_now()),
                                          cmdfileUrl)
        logger.warning("EXEC_CMD Request: {}".format(xml))
        headers = {"content-type": "text/xml", "SOAPAction": "application/soap+xml;charset=utf8"}
        try:
            response = requests.post(self.cms_api, data=xml, headers=headers).content
            logger.warning("EXEC_CMD Response: {}".format(response))
            tree = ET.fromstring(response)
            # code = tree.find(".//Result").text
            msg = tree.find(".//ErrorDescription").text

            if msg.lower() == "success":
                status = TaskStatusValue.FILE_TRANSFERING
                remark = ""
            else:
                if str(msg).lower().__contains__("could not connect") and count < self.try_count:
                    return self.exec_cmd(task_id, count)
                status = TaskStatusValue.FILE_FAILED
                remark = msg
        except Exception as e:
            status = TaskStatusValue.FILE_FAILED
            remark = "e:{}".format(e)

        TaskModel.objects.filter(pk=task_id).update(status=status, remark=remark[:120])
        return status

    # 介质注入
    def injector(self, task):
        status, flag = 0, 0
        # 如果工单状态 在 pending 在就绪状态，我们就继续
        if task.status in (TaskStatusValue.FILE_PENDING, TaskStatusValue.INFO_PENDING):
            # 组成一新的task_id  在全局中唯一 taskId_00
            _task_id = self.generate_correlate_id(task.id)
            # 生成新的xml
            self.save_album_xml_file(self.csp_id, _task_id, param="program")
            status = self.exec_cmd(task.id)
            flag = self.get_continue_to_injector(status)
        return status, flag

    # 介质注入更新
    def update(self, task):
        if task.status in (TaskStatusValue.FILE_PENDING, TaskStatusValue.INFO_PENDING):
            _task_id = self.generate_correlate_id(task.id)
            self.save_album_xml_file(self.csp_id, _task_id, param="program", action="UPDATE")
            self.exec_cmd(task.id)

    # 介质注入删除
    def remove(self, task):
        if task.status in (TaskStatusValue.FILE_PENDING, TaskStatusValue.INFO_PENDING):
            _task_id = self.generate_correlate_id(task.id)
            self.save_album_xml_file(self.csp_id, _task_id, param="program", action="DELETE")
            self.exec_cmd(task.id)
            self.off_line_storage(task.partner_id, task.storage_id)
            logger.warning("{} 下线媒体: {}, task_id: {}".format(self.partner_alias, task.storage_id, task.id))

    # 更新 剧头
    def series_header_update(self, sync):
        self.series_header_injector(sync)

    # 删除 剧头  目前 广西移动 没有给cp 删除权限
    def series_header_remove(self, sync):
        self.series_header_injector(sync)

    # 注入分类、题材
    def injector_category_handler(self, sync, genre, parent_genre, action):
        if parent_genre:
            third_name = genre.name
            category_name = parent_genre.alias
        else:
            category_name = genre.alias
            third_name = None
        self.series_category_injector(sync, category_name, third_name, action)

    # 注入 免费包、收费包
    def injector_package_handler(self, sync, package_id, action):
        name = self.package_map[package_id]["name"]
        code = self.package_map[package_id]["code"]
        self.series_package_injector(sync, name, code, action)

    #  对剧头进行绑定、解绑 分类
    def bind_category_handler(self, sync, genre, parent_genre, action):
        category_name = parent_genre.alias
        self.series_category_bind(sync, category_name, genre, action)

    def bind_task_category_handler(self, sync, genre, parent_genre, action):
        category_name = parent_genre.alias
        self.series_category_bind(sync, category_name, genre, action)

