import re
import time
import logging
import requests
import datetime
import os

from PIL import Image
from lxml import etree
from injector.models import TaskModel
from injector.models import MediaInfoSyncModel
from domain.lsp.generated.anhuizx_xsd import Adi
from domain.lsp.base_injector import LspInjectorC2
from domain.lsp.value_object import C2ApiUtil
from domain.injector.value_object import TaskStatusValue, ContentTypeValue
from domain.injector.value_object import DefinitionValue

from utils.date_utils import datetime_now

logger = logging.getLogger("django")


class CodeFactory:
    Series = "11"
    Program = "12"
    Movie = "13"
    Picture = "14"
    Cast = "15"
    CastRoleMap = "16"
    Package = "17"
    Channel = "18"
    PhysicalChannel = "19"
    Schedule = "20"

    Picture_Ver = "21"  # 媒资图片横图，伪id的类别
    Picture_Hor = "22"  # 分集剧照信息，伪id类别
    Picture_Third = "31"
    Picture_Four = "32"

    Task = "23"  # 注入任务id的类别

    CAST_MAPPING = {"Actor": "61", "Director": "62", "ScreenWriter": "63"}

    def __init__(self, csp_id, max_len=32):
        self.csp_id = csp_id
        self.max_len = max_len

    def __generate_code__(self, category, some_id):
        fmt = "{0}_{1}_{2}"
        code = fmt.format(self.csp_id, category, some_id)
        before, after = code.rsplit("_", 1)
        after = after.rjust(self.max_len - len(before), "0")
        before = before.replace("_", "0")
        return before + after

    def gen_series_code(self, media_id):
        return self.__generate_code__(self.Series, media_id)

    def gen_program_code(self, storage_id):
        return self.__generate_code__(self.Program, storage_id)

    def gen_movie_code(self, storage_id):
        return self.__generate_code__(self.Movie, storage_id)

    def gen_media_vpic_code(self, media_id):
        return self.__generate_code__(self.Picture_Ver, media_id)

    def gen_media_hpic_code(self, media_id):
        return self.__generate_code__(self.Picture_Hor, media_id)

    def gen_media_third_pic_code(self, media_id):
        return self.__generate_code__(self.Picture_Third, media_id)

    def gen_media_four_pic_code(self, media_id):
        return self.__generate_code__(self.Picture_Four, media_id)

    def gen_program_pic_code(self, storage_id):
        return self.__generate_code__(self.Picture, storage_id)

    def gen_cast_code(self, _type, cast_id):
        _cast = "{}_{}".format(self.Cast, self.CAST_MAPPING[_type])
        return self.__generate_code__(_cast, cast_id)

    def gen_cast_role_map_code(self, _type, role_id):
        _map = "{}_{}".format(self.CastRoleMap, self.CAST_MAPPING[_type])
        return self.__generate_code__(_map, role_id)

    def gen_package_code(self, media_id):
        return self.__generate_code__(self.Package, media_id)

    def gen_task_code(self, task_id):
        return self.__generate_code__(self.Task, task_id)


class XiZangDianXin(LspInjectorC2):

    def __init__(self, alias="XIZANGDIANXIN"):
        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.code_factory = CodeFactory(self.csp_id)
        self.image_file_dir = "/home/sftp-user/vdb/xml_home"
        self.cast_sep = " "
        self.genre_sep = ";"
        self.package_free = "50010108017000000000000000005824"
        self.package_vip = "50010108017000000000000000005759"
        self.third_pic_size = (255, 193)
        self.four_pic_size = (1280, 580)
        self.description_prefix = "（来源森宇文化）"
        self.old_remove = False

    def get_content_type(self, content_type):
        return {
            ContentTypeValue.POSITIVE: "0",
            ContentTypeValue.CLIP: "1",
            ContentTypeValue.TRAILER: "1"
        }.get(content_type, "0")

    def _get_bit_rate_type(self, definition):
        BIT_RATE_TYPE_MAP = {
            DefinitionValue.P320: 3,  # 2/3 D1
            DefinitionValue.P480: 5,  # D1
            DefinitionValue.P720: 6,  # 720P
            DefinitionValue.P1080: 8,  # 1080P
            DefinitionValue.P3840: 9,  # 4K(3840*2160)
            DefinitionValue.P4096: 10,  # 4K(4096*2160)
            DefinitionValue.K4: 10  # 4K(4096*2160)
        }
        return BIT_RATE_TYPE_MAP.get(definition, 3)

    def zoom_picture(self, file_path, pic_url, size):
        tmp_file_name = file_path.split("/")[-1]
        relative_file_dir = file_path.split(tmp_file_name)[0]

        name, suffix = re.split("\.", tmp_file_name)
        width, height = size

        tmp_file_path = os.path.join(self.image_file_dir, file_path)
        file_dir = tmp_file_path.split(tmp_file_name)[0]

        file_name = "{}_{}x{}.{}".format(name, width, height, suffix)
        file_path = os.path.join(file_dir, file_name)

        if not os.path.exists(file_path):
            os.makedirs(file_dir, exist_ok=True)
            r = requests.get(pic_url)
            with open(tmp_file_path, "wb") as f:
                f.write(r.content)
            image = Image.open(tmp_file_path)
            # 打开指定路径的jpg图像文件
            out = image.resize((width, height))
            out.save(file_path)
            os.remove(tmp_file_path)
        return "{}{}".format(relative_file_dir, file_name)

    # 将图片地址转成ftp
    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("partner", "partner", "47.110.47.81",
                                                        "2121", file_path)
        return storage_ftp_url

    def bit_rate_transform(self, bit_rate):
        BIT_RATE_MAP = {1634.8: 1, 2150.4: 2, 8192: 3, 60: 4, 150: 5, 420: 6, 750: 7}
        BRM = [60, 150, 420, 750, 1634.8, 2150.4, 8192]
        _new_bit_poor = [abs(bit_rate - i) for i in BRM]
        min_poor = min(_new_bit_poor)
        min_bit = BRM[_new_bit_poor.index(min_poor)]
        return BIT_RATE_MAP.get(min_bit)

    def episode_no_header(self, media):
        print("category:{}".format(media.category))
        return media.category not in ("documentary",)
    def change_duration(self, seconds):

        return datetime.timedelta(seconds=seconds)

    def v_codec_transform(self, v_codec):
        V_CODEC_MAP = {
            "h264": 1,  # H.264
            "mpeg4": 2,  # MPEG4
            "mpeg2video": 4  # MPEG2
        }
        return V_CODEC_MAP.get(v_codec, 2)

    def property_cast(self, cast_id, name, action):
        the_property = [
            {"Name": name},
            {"PersonSortName": name},
            {"PersonDisplayName": name},
            {"FirstName": name[0]},
            {"Sex": "1"}
        ]

        return {
            "element_type": "Cast",
            "id": cast_id,
            "code": cast_id,
            "action": action,
            "property": the_property
        }

    def property_cast_role_map(self, cast_id, role, role_id, action):
        the_property = [
            {"CastRole": role},
            {"CastCode": cast_id},
            {"CastID": cast_id}
        ]

        return {
            "element_type": "CastRoleMap",
            "id": role_id,
            "code": role_id,
            "action": action,
            "property": the_property
        }

    def get_language(self, language):

        if language.__contains__("普通话"):
            return "国语"
        return language

    def get_description(self, desc):
        return self.description_prefix + desc

    def join_names(self, objs):
        names = [obj.celebrity.name for obj in objs if obj.celebrity.name != "佚名"]
        join_str = self.cast_sep.join(names)
        return join_str

    def property_common(self, media):
        name = self.get_media_name_by_alias(media).replace(" ", "")
        search_name = self.transform_chinese_to_letter(name)
        param_dict = {"category": media.category, "is_charge": 1}
        change_fields = self.injected_change.get_injected_fields(media.id, self.lsp_pk, param_dict)
        actors, directors, writers = self.get_media_person(media, actor=4, director=4, writer=2)
        vst, vet = self.get_media_effective_time(media.id)
        the_property = [
            {"OriginalName": name},
            {"SortName": search_name},
            {"SearchName": search_name},
            {"DefinitionFlag": "1"},
            {"Genre": self.get_genre(media)},
            {"Director": directors},
            {"ActorDisplay": actors},
            {"WriterDisplay": writers},
            {"OrgAirDate": "".join(media.date_published.split("-"))},
            {"ReleaseYear": media.year},
            {"Language": self.get_language(media.languages)},
            {"OriginalCountry": self.get_regions(media)},
            {"Status": 1},
            {"Description": self.get_description(media.storyline)},
            {"Macrovision": 1},
            {"Type": self._get_category_desc(change_fields["category"])},
            {"Tags": self.get_genre(media)},
            {"LicensingWindowStart": vst},
            {"LicensingWindowEnd": vet}
        ]

        return the_property

    def property_series(self, _id, volumn_count, media, action="REGIST"):
        the_property = self.property_common(media)
        the_property.extend([
            {"Name": self.get_media_name_by_alias(media)},
            {"VolumnCount": volumn_count},
        ])
        return {
            "element_type": "Series",
            "id": _id,
            "code": _id,
            "action": action,
            "property": the_property
        }

    def split_cast(self, list_str):
        cast_list = []
        if list_str:
            list_str = list_str.strip()
            cast_list = list_str.split(self.cast_sep)
            cast_list = [i for i in cast_list if i]
        return cast_list

    def gen_episode_title(self, name, num):
        return "{}[{}]".format(name, num)

    def property_program(self, _id, media, name, flag, action="REGIST"):
        the_property = self.property_common(media)
        the_property.extend([{"Name": name}, {"SourceType": 1}, {"SeriesFlag": flag}, {"PriceTaxIn": 0}])
        return {
            "element_type": "Program",
            "id": _id,
            "code": _id,
            "action": action,
            "property": the_property
        }

    def format_duration_rate(self, seconds, frame):
        duration = time.strftime("%H%M%S", time.gmtime(seconds))
        return "{}{}".format(duration, frame)

    def property_movie(self, _id, media_storage, _type=1, action="REGIST"):
        return {
            "element_type": "Movie",
            "id": _id,
            "code": _id,
            "action": action,
            "property": [
                {"Type": _type},
                {"FileURL": self.get_storage_ftp_url(media_storage.url)},
                {"AudioType": self.get_audio_type(media_storage.a_codec)},
                {"ClosedCaptioning": 1},
                {"Duration": self.format_duration_rate(media_storage.seconds, media_storage.frame_rate)},
                {"BitRateType": self.bit_rate_transform(media_storage.bit_rate)},
                {"VideoType": self.v_codec_transform(media_storage.v_codec)},
                {"AudioFormat": 2},
                {"Resolution": self._get_bit_rate_type(media_storage.definition)},
                {"SystemLayer": 1},
                {"FileSize": str(media_storage.size)}
            ]
        }

    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 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_package(self, _id, media, action):
        vst, vet = self.get_media_effective_time(media.id)
        param_dict = {"category": media.category, "is_charge": 1}
        # change_fields = self.injected_change.get_injected_fields(media.id, self.lsp_pk, param_dict)
        # is_charge = change_fields["is_charge"]
        the_property = [
            {"LicensingWindowStart": vst},
            {"LicensingWindowEnd": vet},
            {"Status": "1"}
        ]
        # if int(is_charge) == 0:
        #     the_property.extend(self.package_free)
        # else:
        #     the_property.extend(self.package_vip)
        return {
            "element_type": "Package",
            "id": _id,
            "code": _id,
            "action": action,
            "property": the_property
        }

    def scan_cast(self, name_list, media_id, _type, cast_list, role_map_list, action):
        for i in range(len(name_list)):
            name = name_list[i]
            cast_id = self.code_factory.gen_cast_code(_type, str(media_id) + str(i))
            role_id = self.code_factory.gen_cast_role_map_code(_type, str(media_id) + str(i))
            p_cast = self.property_cast(cast_id, name, action)
            p_cast_role_map = self.property_cast_role_map(cast_id, _type, role_id, action)
            cast_list.append(p_cast)
            role_map_list.append(p_cast_role_map)

    def scan_cast_role_id(self, name_list, media_id, _type, id_list):
        for i in range(len(name_list)):
            role_id = self.code_factory.gen_cast_role_map_code(_type, str(media_id) + str(i))
            id_list.append(role_id)

    def casts(self, media, action):
        actors, directors, writers = self.get_media_person(media, actor=4, director=4, writer=2)
        actor_list = self.split_cast(actors)
        director_list = self.split_cast(directors)
        writer_list = self.split_cast(writers)

        cast_list = []
        role_map_list = []
        self.scan_cast(actor_list, media.id, "Actor", cast_list, role_map_list, action)
        self.scan_cast(director_list, media.id, "Director", cast_list, role_map_list, action)
        self.scan_cast(writer_list, media.id, "ScreenWriter", cast_list, role_map_list, action)
        # return {
        #     "domain": "0",
        #     "object_list": cast_list + role_map_list,
        #     "mapping_list": []
        # }
        # xml = Adi.to_xml(data, flag="Nope")
        # return xml
        return cast_list + role_map_list

    def get_cast_role_ids(self, media):
        actors, directors, writers = self.get_media_person(media, actor=4, director=4, writer=2)

        actor_list = self.split_cast(actors)
        director_list = self.split_cast(directors)
        writer_list = self.split_cast(writers)

        cast_role_id_list = []
        self.scan_cast_role_id(actor_list, media.id, "Actor", cast_role_id_list)
        self.scan_cast_role_id(director_list, media.id, "Director", cast_role_id_list)
        self.scan_cast_role_id(writer_list, media.id, "ScreenWriter", cast_role_id_list)

        return cast_role_id_list

    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 change_action_update_to_register(self, action):
        if action == "UPDATE":
            return "REGIST"
        return action

    def _album_series_header(self, media, media_ext, info_sync):
        action = self.change_action_update_to_register(info_sync.action_description())
        _episodes = int(media.episodes) if media.episodes else 0
        media_verpic = media_ext.media_verpic
        media_horpic = media_ext.media_horpic
        # 185x265
        size_verpic = self.image_resize.XIZANGDIANXIN.get("verpic")
        # 255*193
        size_horpic = self.image_resize.XIZANGDIANXIN.get("horpic")

        psid = self.code_factory.gen_series_code(media.id)
        p_series = self.property_series(psid, _episodes, media, action=action)

        pspcvid = self.code_factory.gen_media_vpic_code(media.id)

        pspchid = self.code_factory.gen_media_hpic_code(media.id)

        pspthird = self.code_factory.gen_media_third_pic_code(media.id)

        pspfourid = self.code_factory.gen_media_four_pic_code(media.id)
        # 185x265
        verpic_series_picture = self.property_picture(pspcvid, media_verpic, size_verpic, action=action)
        # 255*193
        horpic_series_picture = self.property_picture(pspchid, media_horpic, size_horpic, action=action)

        pic_series_third = self.property_picture(pspthird, media_horpic, self.third_pic_size, action=action)

        pic_series_four = self.property_picture(pspfourid, media_horpic, self.four_pic_size, action=action)

        mapping_series_ver_picture = self.property_mapping("Picture", "Series", pspcvid, psid, _type=1, sequence=1,
                                                           action=action)
        # 255*193
        mapping_series_hor_picture = self.property_mapping("Picture", "Series", pspchid, psid, _type=1, sequence=999,
                                                           action=action)

        mapping_pic_series_third = self.property_mapping("Picture", "Series", pspthird, psid, _type=1, sequence=247,
                                                         action=action)
        mapping_pic_series_four = self.property_mapping("Picture", "Series", pspfourid, psid, _type=1, sequence=678)

        cast_list = self.casts(media, action)

        cast_role_ids = self.get_cast_role_ids(media)
        cast_role_map_list = []
        for _id in cast_role_ids:
            mapping_series_cast_role = self.property_mapping("Series", "CastRoleMap", psid, _id, action=action)
            cast_role_map_list.append(mapping_series_cast_role)

        param_dict = {"category": media.category, "is_charge": 1}
        change_fields = self.injected_change.get_injected_fields(media.id, self.lsp_pk, param_dict)
        is_charge = change_fields.get("is_charge", 0)

        if int(is_charge) == 0:
            mapping_package = self.property_mapping("Package", "Series", self.package_free, psid,
                                                    action=action)
        else:
            mapping_package = self.property_mapping("Package", "Series", self.package_vip, psid,
                                                    action=action)

        return {
            "domain": "0",
            "priority": "1",
            "object_list": [p_series, verpic_series_picture, horpic_series_picture, pic_series_third,
                            pic_series_four] + cast_list,
            "mapping_list": [mapping_series_ver_picture, mapping_series_hor_picture, mapping_pic_series_third,
                             mapping_package, mapping_pic_series_four] + cast_role_map_list
        }

    def _album_sub_series(self, media_storage, media, media_ext, episode, _episodes, action="REGIST"):

        psid = self.code_factory.gen_series_code(media.id)
        if self.old_remove:
            ppid = self.code_factory.gen_program_code(media_storage.id)

        else:
            ppid = self.code_factory.gen_program_code(episode.id)
        name = self.gen_episode_title(self.get_media_name_by_alias(media), episode.serial_num)
        p_program = self.property_program(ppid, media, name, 1, action=action)

        pmid = self.code_factory.gen_movie_code(media_storage.id)
        p_movie = self.property_movie(pmid, media_storage, action=action)
        mapping_movie = self.property_mapping("Program", "Movie", ppid, pmid, action=action)

        mapping_series = self.property_mapping("Series", "Program", psid, ppid, sequence=episode.serial_num,
                                               action=action)

        return {
            "domain": "0",
            "priority": "1",
            "object_list": [p_program, p_movie],
            "mapping_list": [mapping_series, mapping_movie],
        }

    def _album_movie(self, media_storage, media, episode, media_ext, action="REGIST"):

        media_verpic = media_ext.media_verpic
        media_horpic = media_ext.media_horpic
        size_verpic = self.image_resize.ANHUIYIDONG.get("verpic")
        size_horpic = self.image_resize.ANHUIYIDONG.get("horpic")

        if self.old_remove:
            ppid = self.code_factory.gen_program_code(media_storage.id)
        else:
            ppid = self.code_factory.gen_program_code(episode.id)
        p_program = self.property_program(ppid, media, self.get_media_name_by_alias(media), 0, action=action)

        pmid = self.code_factory.gen_movie_code(media_storage.id)
        p_movie = self.property_movie(pmid, media_storage, action=action)
        mapping_movie = self.property_mapping("Program", "Movie", ppid, pmid, action=action)

        pspcvid = self.code_factory.gen_media_vpic_code(media.id)
        pspchid = self.code_factory.gen_media_hpic_code(media.id)
        pspthird = self.code_factory.gen_media_third_pic_code(media.id)
        pspfour = self.code_factory.gen_media_four_pic_code(media.id)
        verpic_series_picture = self.property_picture(pspcvid, media_horpic, size_verpic, action=action)
        horpic_series_picture = self.property_picture(pspchid, media_horpic, size_horpic, action=action)
        pic_series_third = self.property_picture(pspthird, media_verpic, self.third_pic_size, action=action)
        pic_series_four = self.property_picture(pspfour, media_horpic, self.four_pic_size, action=action)
        mapping_series_ver_picture = self.property_mapping("Picture", "Program", pspcvid, ppid, _type=1, sequence=247,
                                                           action=action)
        mapping_series_hor_picture = self.property_mapping("Picture", "Program", pspchid, ppid, _type=1, sequence=999,
                                                           action=action)
        mapping_pic_series_third = self.property_mapping("Picture", "Program", pspthird, ppid, _type=1, sequence=1,
                                                         action=action)
        mapping_pic_series_four = self.property_mapping("Picture", "Program", pspfour, ppid, _type=1, sequence=678)

        package_mapping_list = []
        if 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)
            is_charge = change_fields.get("is_charge", 0)
            if int(is_charge) == 0:
                mapping_package = self.property_mapping("Package", "Program", self.package_free, ppid,
                                                        action=action)
            else:
                mapping_package = self.property_mapping("Package", "Program", self.package_vip, ppid,
                                                        action=action)
            package_mapping_list.append(mapping_package)

        cast_list = self.casts(media, action)

        cast_role_ids = self.get_cast_role_ids(media)
        cast_role_map_list = []
        for _id in cast_role_ids:
            mapping_series_cast_role = self.property_mapping("Program", "CastRoleMap", ppid, _id, action=action)
            cast_role_map_list.append(mapping_series_cast_role)

        return {
            "domain": "0",
            "priority": "1",
            "object_list": [p_program, p_movie, verpic_series_picture, horpic_series_picture,
                            pic_series_third, pic_series_four] + cast_list,
            "mapping_list": [mapping_movie, mapping_series_ver_picture,
                             mapping_series_hor_picture,
                             mapping_pic_series_third,
                             mapping_pic_series_four] + cast_role_map_list + package_mapping_list,
        }

    def album(self, _header_id, action="REGIST"):
        header_id, _ = _header_id.split("_", 1)
        info_sync = MediaInfoSyncModel.objects.filter(pk=header_id).select_related("media").first()
        media = info_sync.media
        media_ext = media.mediaextfieldmodel
        data = self._album_series_header(media, media_ext, info_sync)
        xml = Adi.to_xml(data, flag="Nope")
        return 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  # 媒体文件补充信息
        _episodes = int(media.episodes) if media.episodes else 0
        if _episodes > 1:
            data = self._album_sub_series(media_storage, media, media_ext, episode, _episodes, action)
        else:  # 单剧集
            data = self._album_movie(media_storage, media, episode, media_ext, action)

        xml = Adi.to_xml(data, flag="Nope")

        return xml

    def package_mapping(self, _task_id, action):
        task_id, _ = _task_id.split("_", 1)
        task = TaskModel.objects.filter(pk=task_id).select_related("storage").first()
        media = task.media
        episode = task.episode
        ppid = self.code_factory.gen_program_code(episode.id)
        param_dict = {"category": media.category, "is_charge": 1}
        change_fields = self.injected_change.get_injected_fields(media.id, self.lsp_pk, param_dict)
        is_charge = change_fields.get("is_charge", 0)
        if int(is_charge) == 0:
            mapping_package = self.property_mapping("Package", "Program", self.package_free, ppid,
                                                    action=action)
        else:
            mapping_package = self.property_mapping("Package", "Program", self.package_vip, ppid,
                                                    action=action)
        data = {
            "domain": "0",
            "priority": "5",
            "object_list": [],
            "mapping_list": [mapping_package]
        }

        xml = Adi.to_xml(data, flag="Nope")

        return xml

    def series_package_mapping(self, _task_id, action):
        task_id, _ = _task_id.split("_", 1)
        task = MediaInfoSyncModel.objects.filter(pk=task_id).first()
        media = task.media
        psid = self.code_factory.gen_series_code(media.id)
        param_dict = {"category": media.category, "is_charge": 1}
        change_fields = self.injected_change.get_injected_fields(media.id, self.lsp_pk, param_dict)
        is_charge = change_fields.get("is_charge", 0)
        if int(is_charge) == 0:
            mapping_package = self.property_mapping("Package", "Series", self.package_free, psid,
                                                    action=action)
        else:
            mapping_package = self.property_mapping("Package", "Series", self.package_vip, psid,
                                                    action=action)
        data = {
            "domain": "0",
            "priority": "5",
            "object_list": [],
            "mapping_list": [mapping_package]
        }

        xml = Adi.to_xml(data, flag="Nope")

        return xml

    def save_album_xml_file(self, csp_id, cmd_id, param="series", is_movie=False, action="REGIST"):

        if param == "series":
            xml = self.album(cmd_id, action=action)
        elif param == "package":
            if is_movie:
                xml = self.package_mapping(cmd_id, action)
            else:
                xml = self.series_package_mapping(cmd_id, action)
        else:
            xml = self.program(cmd_id, 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_path(csp_id, cmd_id)
        with open(file_path, "w") as f:
            f.write(xml)

    @staticmethod
    def generate_correlate_id(task_id, stage="common", suffix=None):
        tail = "01"
        if stage == "package":
            tail = "09"
        elif stage != "common":  # 剧头注入阶段
            tail = "00"
        return "{}_{}_{}".format(task_id, tail, suffix) if suffix else "{}_{}".format(task_id, tail)

    def series_package_remove(self, sync):
        header_id = self.generate_correlate_id(sync.id, stage="package")
        self.save_album_xml_file(self.csp_id, header_id, param="package", action="DELETE")
        code = self.exec_sync_header_cmd(sync, "package")
        return code

    def program_package_remove(self, task_id):
        _task_id = self.generate_correlate_id(task_id, stage="package")
        self.save_album_xml_file(self.csp_id, _task_id, param="package", is_movie=True, action="DELETE")
        status = self.exec_cmd(task_id, "package")
        return status

    def log_info(*args):
        info = " ".join(map(str, args))
        return info

    def exec_cmd(self, task_id, stage="common"):
        _task_id = self.generate_correlate_id(task_id, stage=stage)
        cmd_file_url = self.get_cmd_ftp_url(self.csp_id, _task_id)
        cor_id = "{}_{}".format(_task_id, datetime_now())
        xml = C2ApiUtil.REQUESTXML.format(self.csp_id, self.lsp_id, cor_id, cmd_file_url)
        headers = {"content-type": "text/xml", "SOAPAction": "application/soap+xml;charset=utf8"}
        response = requests.post(self.cms_api, data=xml, headers=headers).content
        logger.info(self.log_info(self.conf.alias, self.lsp_id, self.csp_id, cor_id, task_id, stage, response))
        tree = etree.fromstring(response)

        code = tree.findall(".//Result")[0].text
        desc = tree.find(".//ErrorDescription").text
        if int(code) == 0:
            status = TaskStatusValue.INFO_TRANSFERING
            remark = ""
        else:
            status = TaskStatusValue.INFO_FAILED
            remark = desc

        the_task = TaskModel.objects.filter(pk=task_id)
        if the_task.first().status == TaskStatusValue.FILE_PENDING:
            the_task.update(status=status, remark=remark)
        return status

    def exec_sync_header_cmd(self, sync, stage="series"):
        _sync_id = self.generate_correlate_id(sync.id, stage=stage)
        cmd_file_url = self.get_cmd_ftp_url(self.csp_id, _sync_id)
        sync_id = "{}_{}".format(_sync_id, datetime_now())
        """
            平台 lsp  csp  工单号  任何ID  剧头/介质/包  action  结果 
        """
        xml = C2ApiUtil.REQUESTXML.format(self.csp_id, self.lsp_id, sync_id, cmd_file_url)
        headers = {"content-type": "text/xml", "SOAPAction": "application/soap+xml;charset=utf8"}
        response = requests.post(self.cms_api, data=xml, headers=headers).content
        logger.info(self.log_info(self.conf.alias, self.lsp_id, self.csp_id, sync_id, sync.id, stage, response))
        tree = etree.fromstring(response)
        code = tree.findall(".//Result")[0].text
        if int(code) == 0:
            status = MediaInfoSyncModel.SYNCING
        else:
            status = MediaInfoSyncModel.FAILED
        the_sync = MediaInfoSyncModel.objects.filter(pk=sync.id)
        if the_sync.first().status == MediaInfoSyncModel.PENDING:
            the_sync.update(status=status)
        return int(code)

    def injector(self, task):
        status, flag = 0, 0
        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")
            status = self.exec_cmd(task.id)
            flag = self.get_continue_to_injector(status)
        return status, flag

    def update(self, task):  # 要求 子集、单集 更新 也是 REGIST
        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="REGIST")
            self.exec_cmd(task.id)

    def remove(self, task):
        if task.status in (TaskStatusValue.FILE_PENDING, TaskStatusValue.INFO_PENDING):
            # 先进行包删除
            status = self.program_package_remove(task.id)
            if status == TaskStatusValue.INFO_TRANSFERING:
                _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)

    def series_header_injector(self, sync):
        if sync.status == MediaInfoSyncModel.PENDING:
            header_id = self.generate_correlate_id(sync.id, stage="series")
            self.save_album_xml_file(self.csp_id, header_id, param="series")
            self.exec_sync_header_cmd(sync)

    def series_header_update(self, sync):
        self.series_header_injector(sync)

    def series_header_remove(self, sync):
        # 先进行包删除
        # 先删除包
        code = self.series_package_remove(sync)
        if code == 0:
            header_id = self.generate_correlate_id(sync.id, stage="series")
            self.save_album_xml_file(self.csp_id, header_id, param="series")
            self.exec_sync_header_cmd(sync)
