import ftplib
import json
import os
import random
import re
import hashlib
import pypinyin
import logging

import requests
from PIL import Image
from django.conf import settings

import xml.etree.ElementTree as ET

from domain import domain_except
from domain.injector.factory import create_by_alias
from domain.lsp.generated.shanxi_xml import XMLBuilder
from domain.lsp.lsp_domain import Lsp
from domain.imdb.episode_domain import Episode
from domain.imdb.media_domain import Media
from imdb.models import CelebrityRoleValue
from imdb.models import CelebrityMediaRelationModel
from injector.models import TaskModel
from injector.models import MediaInfoSyncModel
from injector.models import MediaExtFieldModel
from injector.models import PartnerMediaStorageModel, OrderBookModel
from domain.imdb.value_object import CategoryValue
from domain.lsp.value_object import CodeFactory, SFtpUrlParameter, LspExtendConfig, FtpUrlParameter, C2ApiUtil
from domain.injector.injected_domain import InjectedFieldChange
from domain.injector.media_storage_domain import MediaStorage
from domain.injector.value_object import RatingValue, DefinitionValue, TaskStatusValue, ContentTypeValue, \
    PlatformAliasValue, TaskModelActionValue
from utils import date_utils
from utils.defines import ResponseCode

logger = logging.getLogger(__file__)


class LspInjectorG:
    HOST = "172.25.129.68"
    IMG_PORT = "8010"

    def __init__(self, alias="alias"):
        self.partner_alias = alias
        self.lsp = Lsp().get_obj_by_alias(alias)
        self.conf = self.lsp
        self.lsp_pk = self.lsp.id
        self.key = ""
        self.salt = ""
        self.image_resize = LspExtendConfig()
        self.injected_change = InjectedFieldChange()

    def check_module_args(self, model, keys):
        for key in keys:
            value = getattr(model, key)
            if not value:
                raise domain_except.ParamRequiredException("缺少必填参数:{}".format(key))

    # 将阿里云的url遇到成本地地址
    def to_ip_url(self, url: str):
        dn = 'senyu-img.oss-cn-hangzhou.aliyuncs.com'
        ip_port = '{}:{}'.format(self.HOST, self.IMG_PORT)
        return url.replace(dn, ip_port)

    def get_media_name_by_alias(self, media):
        if media.partner_alias:
            for alias in media.partner_alias:
                if alias and self.lsp_pk in alias["partner_id"]:
                    return alias["name"]
        return media.name

    def check_media_cast(self, casts, keys):
        roles_dict = {}
        for cast in casts:
            roles_dict[cast.role] = 1

        for key in keys:
            if roles_dict.get(key, 0) == 0:
                raise domain_except.ParamRequiredException("缺少出演人员信息:{}".format(key))

    def make_sign(self, body: str):
        md5 = hashlib.md5("{}{}{}".format(self.key, self.salt, body).encode("utf-8"))
        return md5.hexdigest()

    def get_age_group(self, rating):
        return RatingValue.rating_map()[rating]

    def get_storage_is_show(self, storage_id, partner_id):
        allow_show = PartnerMediaStorageModel.objects.filter(storage_id=storage_id, partner_id=partner_id).first()
        if allow_show:
            return allow_show.is_show
        else:
            return False

    def get_storage_is_show_action(self, storage_id, partner_id, action):
        if action == TaskModelActionValue.UN_ACTIVE:
            return 0
        elif action == TaskModelActionValue.ACTIVE:
            return 1
        else:
            return int(self.get_storage_is_show(storage_id, partner_id))

    def is_movie(self, media):
        if media.episodes == 1:
            return True
        return False

    # 平台下线片单
    def off_line_storage(self, partner_id, storage_id):
        PartnerMediaStorageModel.objects.filter(
            partner_id=partner_id, storage_id=storage_id
        ).update(is_show=0)
        TaskModel.objects.filter(partner_id=partner_id, storage_id=storage_id).update(action=3)
        print("off_line_storage")

    def update_action(self, task_id):
        TaskModel.objects.filter(pk=task_id).update(action=TaskModelActionValue.UPDATE)

    def get_continue_to_injector(self, status):
        return status not in TaskStatusValue.stop_injector()

    # 有分集标题时
    def _have_episode_title(self, media, episode):
        fmt = "第{0}集{1}{2}"
        return fmt.format(episode.serial_num, " ", episode.title)

    # 无分集标题时
    def _nope_episode_title(self, media, episode):
        fmt = "{0}{1}第{2}集"
        return fmt.format(self.get_media_name_by_alias(media), " ", episode.serial_num)

    def get_storage_definition(self, definition, v_codec):
        if definition in (8, 9, 10):
            if v_codec == "h264":
                return 4104
            return 4205
        return definition

    def active_task(self, task, *args):
        return TaskModelActionValue.ACTIVE_NO_EXIST

    def un_active_task(self, task, *args):
        return TaskModelActionValue.ACTIVE_NO_EXIST

    def gen_program_code_by_movie(self, media):
        return "暂无"

    # 根据规则获取分集标题
    def get_episode_title(self, media, episode):
        # 获取注入时变更的媒体类型
        param_dict = {"category": media.category}
        category = self.injected_change.get_injected_fields(media.id, self.lsp_pk, param_dict)["category"]
        if category in CategoryValue.movie_category():  # 电影系列
            title = self.get_media_name_by_alias(media)
        elif category in (CategoryValue.TVSERIES, CategoryValue.CHILDREN,
                          CategoryValue.ANIMATION, CategoryValue.EDUCATION,
                          CategoryValue.GAME):
            # 电视剧、少儿(儿童)、动漫、教育、游戏
            if episode.title:
                title = self._have_episode_title(media, episode)
            else:
                title = self._nope_episode_title(media, episode)
        elif category in (CategoryValue.VARIETY, CategoryValue.SHORT_FILM, CategoryValue.DOCUMENTARY):
            title = "{} {}期".format(self.get_media_name_by_alias(media), episode.serial_num)
        else:
            title = "{} {}".format(self.get_media_name_by_alias(media), episode.title)
        return title


class LspInjectorC2:
    HOST = "47.110.47.81"
    IMG_PORT = "8010"
    FTP_PREFIX = '/vdb/xml_home'
    XML_FILE_DIR = '/home/sftp-user/vdb/xml_home'
    XML_FILE_APP_DIR = '/app/files'
    IMAGE_FILE_DIR = '/home/sftp-user/vdb/xml_home'
    IMAGE_FILE_APP_DIR = '/app/files'
    FTP_STORAGE_USER = "senyucp"
    FTP_STORAGE_PASSWORD = "Sy_pKw69A8"
    FTP_STORAGE_HOST = "111.2.18.142"
    FTP_STORAGE_PORT = "2121"
    # 检查参数
    Media_Required_Args = ("episodes", "name", "date_published", "category", "genres", "regions",
                           "storyline", "total_seconds", "languages", "year")
    Episode_Required_Args = ("serial_num", "episode_horpic")
    Video_Required_Args = ("url", "a_codec", "definition")
    MediaExt_Required_Args = ("media_horpic",)

    def __init__(self, alias="alias"):
        self.partner_alias = alias
        self.conf = Lsp().get_obj_by_alias(alias)
        self.lsp_pk = self.conf.id
        self.cast_sep = ","
        self.region_sep = ","
        self.genre_sep = ","
        self.tag_sep = ";"
        self.image_resize = LspExtendConfig()
        self.injected_change = InjectedFieldChange()
        self.ips = ["111.2.18.142:8081", "112.16.171.210:8086"]
        self.is_divide_series = False
        self.is_cdn_xml = False
        self.try_count = 3
        self.all_series_first = False

    def get_content_type(self, content_type):
        return {
            ContentTypeValue.POSITIVE: "正片",
            ContentTypeValue.CLIP: "花絮",
            ContentTypeValue.TRAILER: "预告片"
        }.get(content_type, "正片")

    def check_module_args(self, model, keys):
        for key in keys:
            value = getattr(model, key)
            if not value:
                raise domain_except.ParamRequiredException("缺少必填参数:{}".format(key))

    def check_series_header_args(self, media_id):
        media_ext = MediaExtFieldModel.objects.get(media_id=media_id)
        media_ext_args = ("media_horpic", "media_verpic")
        self.check_module_args(media_ext, media_ext_args)
        return

    def check_args(self, storage_id):
        """校验参数是不是全"""
        video = MediaStorage.model.objects.select_related('media', 'episode').get(id=storage_id)
        self.check_module_args(video.media, self.Media_Required_Args)
        self.check_module_args(video.episode, self.Episode_Required_Args)
        self.check_module_args(video, self.Video_Required_Args)
        self.check_module_args(video.media.mediaextfieldmodel, self.MediaExt_Required_Args)
        return

    def get_media_name_by_alias(self, media):
        if media.partner_alias:
            for alias in media.partner_alias:
                if alias and self.lsp_pk in alias["partner_id"]:
                    return alias["name"]
        return media.name

    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_episode_effective_time(self, media_id, serial_num):
        effective_time = Episode.get_episode_effective_time(media_id, serial_num, self.lsp_pk)
        start_date = effective_time["start_date"]
        end_date = effective_time["end_date"]
        if not (start_date and end_date):
            return "", ""

        start_time = "{}000000".format(start_date.replace("-", ""))
        end_time = "{}235959".format(end_date.replace("-", ""))
        return start_time, end_time

    # 获取所有分集的时间总长，一般为series用
    def get_media_effective_time(self, media_id):
        effective_time = Episode.get_media_effective_time(media_id, self.lsp_pk)
        start_date = effective_time["start_date"]
        end_date = effective_time["end_date"]
        if not (start_date and end_date):
            return "", ""

        start_time = "{}000000".format(start_date.replace("-", ""))
        end_time = "{}235959".format(end_date.replace("-", ""))
        return start_time, end_time

    def get_media_effective_time_date(self, media_id):
        effective_time = Episode.get_media_effective_time(media_id, self.lsp_pk)
        start_date = effective_time["start_date"]
        end_date = effective_time["end_date"]
        if not (start_date and end_date):
            return "", ""
        start_time = start_date
        end_time = end_date
        return start_time, end_time

    def get_media_effective_time_line(self, media_id):
        effective_time = Episode.get_media_effective_time(media_id, self.lsp_pk)
        start_date = effective_time["start_date"]
        end_date = effective_time["end_date"]
        if not (start_date and end_date):
            return "", ""

        start_time = "{} 00:00:00".format(start_date)
        end_time = "{} 23:59:59".format(end_date)
        return start_time, end_time

    def change_storage_url(self, url):
        url = re.sub("(\d+?\.+\d+?\.+\d+?\.+\d+?:\d+)", self.ips[1], url)
        return url

    def get_regions(self, media_obj):
        regions = media_obj.regions
        if regions and len(regions):
            names = [region["name"] for region in regions]
            return self.region_sep.join(names)
        return ""

    def get_genre(self, media_obj):
        genres = media_obj.genres
        if genres and len(genres):
            names = [genre["name"] for genre in genres]
            return self.genre_sep.join(names)
        return ""

    def join_names(self, objs):
        names = [obj.celebrity.name for obj in objs]
        join_str = self.cast_sep.join(names)
        return join_str

    def _get_category_desc(self, category):
        if category == CategoryValue.CHILDREN:
            return "少儿"
        return CategoryValue.desc(category)

    def _get_category_desc_o(self, category):
        return CategoryValue.desc(category)

    # 将阿里云的url遇到成本地地址
    def to_ip_url(self, url: str):
        dn = 'senyu-img.oss-cn-hangzhou.aliyuncs.com'
        ip_port = '{}:{}'.format(self.HOST, self.IMG_PORT)
        return url.replace(dn, ip_port)

    # 将介质的http地址转换为ftp地址
    def get_storage_ftp_url(self, http_url):
        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_series_code_by_media(self, media_id):
        return "暂无"

    def get_cmd_sftp_url(self, csp_id, task_id):
        today = date_utils.today().strftime("%Y%m%d")
        file_name = "{}_{}.xml".format(csp_id, task_id)
        full_path = "{}/{}/{}".format(self.partner_alias, today, file_name)
        sftp_url = "sftp://{}:{}@{}{}/{}".format(
            SFtpUrlParameter.USERNAME, SFtpUrlParameter.PASSWORD, self.HOST, self.FTP_PREFIX, full_path
        )
        return sftp_url

    def get_cmd_ftp_url(self, csp_id, task_id):
        today = date_utils.today().strftime("%Y%m%d")
        file_name = "{}_{}.xml".format(csp_id, task_id)
        full_path = "{}/{}/{}".format(self.partner_alias, today, file_name)
        ftp_url = "ftp://{}:{}@{}:{}/{}".format(
            FtpUrlParameter.USERNAME, FtpUrlParameter.PASSWORD, self.HOST, FtpUrlParameter.PORT, full_path
        )
        return ftp_url

    def gen_cmd_ftp_url(self, xml_url):
        ftp_url = "ftp://{}:{}@{}:{}/{}".format(
            FtpUrlParameter.USERNAME, FtpUrlParameter.PASSWORD, self.HOST, FtpUrlParameter.PORT, xml_url
        )
        return ftp_url

    def get_cmd_http_url(self, task_id, view="media", action="REGIST"):
        port = 80
        if settings.DEBUG:
            port = 8000
        if view == "media":
            url = "http://{}:{}/injector/{}/{}?partner={}".format(self.HOST, port, view, task_id, self.partner_alias)
        else:
            url = "http://{}:{}/injector/{}/{}/{}?partner={}".format(
                self.HOST, port, view, task_id, action, self.partner_alias
            )
        return url

    def get_xml_file_dir_path(self):
        today = date_utils.today().strftime("%Y%m%d")
        dir_path = "{}/{}/{}".format(self.XML_FILE_DIR, self.partner_alias, today)  # sftp
        return dir_path

    def get_xml_file_dir_app_path(self):
        today = date_utils.today().strftime("%Y%m%d")
        dir_path = "{}/{}/{}".format(self.XML_FILE_APP_DIR, self.partner_alias, today)  # sftp
        os.makedirs(dir_path, exist_ok=True)
        return dir_path

    def get_xml_file_path(self, csp_id, task_id):
        dir_path = self.get_xml_file_dir_path()
        file_name = "{}_{}.xml".format(csp_id, task_id)
        full_path = "{}/{}".format(dir_path, file_name)
        return full_path

    def get_xml_file_app_path(self, csp_id, task_id):
        dir_path = self.get_xml_file_dir_app_path()
        file_name = "{}_{}.xml".format(csp_id, task_id)
        full_path = "{}/{}".format(dir_path, file_name)
        return full_path

    @staticmethod
    def sub_path_from_url(url, flag=None):
        r = re.sub("http[s]?://\d+\.\d+\.\d+\.\d+:\d+/", "", url)
        if flag:
            r = r.replace("/", flag)
        return r

    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_APP_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", self.HOST,
                                                        "2121", file_path)
        return storage_ftp_url

    # 对于先注入剧头的合作商，标识剧头注入，没有剧头要求的话，标识子集注入
    def album(self, cmd_id, action="REGIST"):
        return "<xml></xml>"

    # 只针对于有剧头注入的合作商，标识子集注入
    def program(self, cmd_id, action="REGIST"):
        return self.album(cmd_id, action)

    def save_album_xml_file(self, csp_id, cmd_id, param="series", action="REGIST"):
        xml = self.album(cmd_id, action=action) if param == "series" else self.program(cmd_id, action)
        print(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(csp_id, cmd_id)
        with open(file_path, "w") as f:
            f.write(xml)
        ftp_url = file_path.split(self.XML_FILE_APP_DIR)[-1]
        return ftp_url

        # 区分剧头类|非剧头类cor_id

    def save_program_xml_file(self, csp_id, cmd_id, action, *args):
        xml = self.program(cmd_id, action, *args)
        print(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_path(csp_id, cmd_id)
        with open(file_path, "w") as f:
            f.write(xml)
        ftp_url = file_path.split(self.XML_FILE_DIR)[-1]
        return ftp_url

    @staticmethod
    def generate_correlate_id(task_id, stage="common", suffix=None):
        tail = "01"
        if stage != "common":  # 剧头注入阶段
            tail = "00"
        return "{}_{}_{}".format(task_id, tail, suffix) if suffix else "{}_{}".format(task_id, tail)

    @staticmethod
    def get_task_id_from_correlate_id(correlate_id):
        return correlate_id.split("_")[0]

    def exec_sync_header_cmd(self, header_id):
        return 0

    def gen_program_code_by_movie(self, media):
        return "暂无"

    def get_media_person(self, media_obj, actor=5, director=5, writer=5):
        media_id = media_obj.id
        _actors = CelebrityMediaRelationModel.objects.filter(
            media_id=media_id, role=CelebrityRoleValue.ACTOR).select_related("celebrity")[:actor]
        _directors = CelebrityMediaRelationModel.objects.filter(
            media_id=media_id, role=CelebrityRoleValue.DIRECTOR).select_related("celebrity")[:director]
        _writers = CelebrityMediaRelationModel.objects.filter(
            media_id=media_id, role=CelebrityRoleValue.AUTHOR).select_related("celebrity")[:writer]
        actors, directors, writers = self.join_names(_actors), self.join_names(_directors), self.join_names(_writers)
        return actors, directors, writers

    # 有分集标题时
    def _have_episode_title(self, media, episode):
        fmt = "第{0}集{1}{2}"
        return fmt.format(episode.serial_num, " ", episode.title)

    # 无分集标题时
    def _nope_episode_title(self, media, episode):
        fmt = "{0}{1}第{2}集"
        return fmt.format(self.get_media_name_by_alias(media), " ", episode.serial_num)

    # 根据规则获取分集标题
    def get_episode_title(self, media, episode):
        # 获取注入时变更的媒体类型
        param_dict = {"category": media.category}
        category = self.injected_change.get_injected_fields(media.id, self.lsp_pk, param_dict)["category"]
        if category in CategoryValue.movie_category():  # 电影系列
            title = self.get_media_name_by_alias(media)
        elif category in (CategoryValue.TVSERIES, CategoryValue.CHILDREN,
                          CategoryValue.ANIMATION, CategoryValue.EDUCATION,
                          CategoryValue.GAME):
            # 电视剧、少儿(儿童)、动漫、教育、游戏
            if episode.title:
                title = self._have_episode_title(media, episode)
            else:
                title = self._nope_episode_title(media, episode)
        elif category in (CategoryValue.VARIETY, CategoryValue.SHORT_FILM, CategoryValue.DOCUMENTARY):
            title = "{} {}期".format(self.get_media_name_by_alias(media), episode.serial_num)
        else:
            title = "{} {}".format(self.get_media_name_by_alias(media), episode.title)
        return title

    def gen_episode_title_by_num(self, episode_num):
        return f"第{episode_num}集"

    # 汉字转换成首字母小写拼音
    def transform_chinese_to_letter(self, the_str):
        _letter = pypinyin.pinyin(the_str, style=pypinyin.FIRST_LETTER)
        result = [str(_letter[index][0]).lower() for index, _ in enumerate(_letter)]
        return "".join(result)

    def get_audio_type(self, a_codec):
        return 5 if a_codec == "ac3" else 2

    def _get_bit_rate_type(self, definition):
        if definition == DefinitionValue.P320:
            return 51
        elif definition == DefinitionValue.P480:
            return 52
        elif definition == DefinitionValue.P720:
            return 53
        elif definition == DefinitionValue.P1080:
            return 54
        elif definition == DefinitionValue.K4:
            return 56
        return 51

    def property_mapping(self, p_type, e_type, pid, eid, _type=1, sequence=None, 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
        }
        sub_property = list()
        if sequence is not None:
            sub_property.extend([{"Sequence": sequence}, ])
        if p_type == "Picture":
            sub_property.extend([{"Type": _type}, ])
        if sub_property:
            the_map["property"] = sub_property
        return the_map

    def get_continue_to_injector(self, status):
        """获取是否继续注入流程flag，C2为一个流程,所以直接返回False"""
        return False

    # 子集和电影回调
    def callback_program(self, code, task_id, res_furl):
        if int(code) == 0:
            task_status = TaskStatusValue.INFO_COMPLETED
        else:
            task_status = TaskStatusValue.INFO_FAILED
            logger.error(
                "{} 子集|电影 回调失败: task_id: {}, result_file_url: {}".format(self.partner_alias, task_id, res_furl))
        TaskModel.objects.filter(pk=task_id).update(status=task_status)
        code = ResponseCode.SUCCESS.value
        desc = ResponseCode.SUCCESS.desc
        return code, desc

    # 剧头回调
    def callback_album(self, code, header_id, res_furl):
        if int(code) == 0:
            status = MediaInfoSyncModel.FINISH
        else:
            status = MediaInfoSyncModel.FAILED
            logger.error(
                "{} 剧头 回调失败: header_id: {}, result_file_url: {}".format(self.partner_alias, header_id, res_furl))
        MediaInfoSyncModel.objects.filter(pk=header_id).update(status=status)
        code = ResponseCode.SUCCESS.value
        desc = ResponseCode.SUCCESS.desc
        return code, desc

    def callback(self, request_body):
        logger.warning("{} 回执请求体内容 {}".format(self.partner_alias, request_body))
        params = C2ApiUtil.callback_params_config(self.partner_alias)
        re_correlate_id = params["correlate_id"]
        re_cmd_result = params["cmd_result"]
        re_result_file_url = params["result_fileURL"]
        re_response_xml = params["response_xml"]
        try:
            tree = ET.fromstring(request_body)
            _correlate_id = tree.find(re_correlate_id).text
            code = tree.find(re_cmd_result).text
            result_file_url = tree.find(re_result_file_url).text
            cor_id, flag, _ = _correlate_id.split("_")
            text_flag = "剧头" if flag == "00" else "子集|电影"
            if cor_id:
                if flag == "00":
                    code, desc = self.callback_album(code, cor_id, result_file_url)
                else:
                    code, desc = self.callback_program(code, cor_id, result_file_url)
            else:
                logger.error(
                    "{} callback 回调错误, code:{}, {}: id: {}".format(self.partner_alias, code, cor_id, text_flag))
                code = -1
                desc = ResponseCode.PARAM_ERROR.desc
        except Exception:
            code, desc = -1, "未携带xml报文体,xml解析失败."
        xml = re_response_xml.format(desc, code)
        logging.warning("callback_response_xml:{}".format(xml))
        return xml

    # 平台下线片单
    def off_line_storage(self, partner_id, storage_id):
        PartnerMediaStorageModel.objects.filter(
            partner_id=partner_id, storage_id=storage_id
        ).update(is_show=0)
        TaskModel.objects.filter(partner_id=partner_id, storage_id=storage_id).update(
            action=TaskModelActionValue.DELETE)

    def update_storage(self, partner_id, storage_id):
        TaskModel.objects.filter(partner_id=partner_id, storage_id=storage_id).update(
            action=TaskModelActionValue.UPDATE)

    # 注入REGIST工单
    def injector(self, task):
        pass

    # 更新UPDATE工单
    def update(self, task):
        pass

    # 删除DELETE工单
    def remove(self, task):
        pass

    # 判断哪些类型支持 单集剧头注入
    def episode_no_header(self, *args):
        return True


class Cast:
    def __init__(self, csp_id):
        self.csp_id = csp_id
        self.code_factory = CodeFactory(self.csp_id)
        pass

    def _get_first_name(self, name):
        if "·" in name:
            return name.split("·")[0]
        else:
            return name[0]

    def cast(self, celebrity_list, cast_list, action):
        for i in celebrity_list:
            name = i.name
            tmp = {
                "property": [
                    {"Name": name},
                    {"FirstName": self._get_first_name(name)}
                ],
                "element_type": "Cast",
                "id": self.code_factory.gen_cast_code(i.id),
                "code": self.code_factory.gen_cast_code(i.id),
                "action": action
            }
            if tmp not in cast_list:
                cast_list.append(tmp)

    def cast_role_map(self, celebrity_list, role_map_list, action, role):
        for i in celebrity_list:
            tmp = {
                "property": [
                    {"CastRole": role},
                    {"CastID": i.id},
                    {"CastCode": i.id}
                ],
                "element_type": "CastRoleMap",
                "id": i.id * 2,
                "code": i.id * 2,
                "action": action
            }
            role_map_list.append(tmp)

    def get_celebrity(self, media, action):
        director_list, actor_list, author_list = Media.get_media_celebrity(media)
        cast_list = []
        self.cast(director_list, cast_list, action)
        self.cast(actor_list, cast_list, action)
        self.cast(author_list, cast_list, action)
        role_map_list = []
        self.cast_role_map(director_list, role_map_list, action, "Director")
        self.cast_role_map(actor_list, role_map_list, action, "Actor")
        self.cast_role_map(author_list, role_map_list, action, "ScreenWriter")
        return cast_list, role_map_list


class MGCallBack:
    def callback_adi(self, body):
        logger.warning("callback_adi : {}".format(body))
        try:
            root = ET.fromstring(body)
            ser_no = root.get("serialNo")
            no_list = ser_no.split("_")
            logger.info("adi no_list:{}".format(no_list))
            if len(no_list) == 4:
                # 执行山西移动
                print("山西移动")
                partner_alias = "SHANXIYIDONG"
            else:
                print("宁夏移动")
                val = no_list[3]
                partner_alias = PlatformAliasValue.get_alias(val)
            logger.info("adi partner_alias:{}".format(partner_alias))
            # 执行宁夏移动  当然以后还可以在细分
            partner = create_by_alias(partner_alias)
            result = partner.callback_adi(body)
        except Exception as e:
            logger.error("adi 执行分发error:{}".format(e))
            status, desc = -1, "未携带xml报文体,xml解析失败."
            result = "{}|{}".format(status, desc)
        return result

    def callback_cdi(self, body):
        logger.warning("callback_cdi: {}".format(body.decode()))
        try:
            tree = ET.fromstring(body)
            attrib = tree.find(".//header").attrib
            sequence = attrib.get("sequence")
            serialNo = attrib.get("serialNo")
            no_list = serialNo.split("_")
            if len(no_list) == 4:
                # 执行山西移动
                partner_alias = "SHANXIYIDONG"
            else:
                val = no_list[3]
                partner_alias = PlatformAliasValue.get_alias(val)
                # 执行宁夏移动  当然以后还可以在细分
            partner = create_by_alias(partner_alias)
            status, desc = partner.callback_cdi(body)
        except Exception as e:
            logger.info("cdi 执行分发error:{}".format(e))
            status, desc = 0, "fail"
        resp = XMLBuilder.build_cdi_response(sequence, status, desc)
        logger.warning("callback_cdi_respones:{}".format(resp))
        return resp

    def callback_strategy(self, body):
        logger.warning("strategy_callback: {}".format(body.decode()))
        json_obj = json.loads(body)
        requestNo = json_obj.get("requestNo")
        no_list = requestNo.split("_")
        if len(no_list) == 4:
            # 执行山西移动
            partner_alias = "SHANXIYIDONG"
            partner = create_by_alias(partner_alias)
            partner.callback(body)
        else:
            val = no_list[3].replace("c", "")
            partner_alias = PlatformAliasValue.get_alias(val)
            # 执行宁夏移动  当然以后还可以在细分
            partner = create_by_alias(partner_alias)
            partner.callback_strategy(body)
        return {"code": 0, "msg": "success"}


class CallbackHandler:

    @classmethod
    def get_alais_from_body(cls, request_body):
        if request_body:
            tree = ET.fromstring(request_body)
            csp = tree.find(".//CSPID").text
            lsp = tree.find(".//LSPID").text
            c_id = tree.find(".//CorrelateID").text
            alias = PlatformAliasValue.LSPALAISMAP.get(lsp, None)
            return alias
        return None


class CallbackAuditHandler:

    @classmethod
    def callback_audit(cls, request_body):
        logger.warning("{} 回执请求体内容 {}".format("callback_audit", request_body))
        # {'list': [{'contentId': 'TYDSKSSM0010000000000000002758', 'contentType': 'S', 'cspId': 'TYDSKSSM', 'result': '1', 'auditMsg': '工单送审失败', 'extInfo': None}]}
        resp_json = json.loads(request_body)
        list_data = []
        for key, val in resp_json.items():
            if isinstance(val, list):
                list_data = val
        result = {"code": "0", "message": "success"}
        if list_data:
            csp_id = list_data[0].get("cspId", None)
            alias = Lsp.model.objects.filter(csp_id=csp_id).values("alias").first().get("alias", None)
            domain = create_by_alias(alias)
            result = domain.callback_audit(list_data)

        return result, True


class CallbackOrderHandler:

    @classmethod
    def get_order_info_from_body(cls, request_body):
        if request_body:
            tree = ET.fromstring(request_body)
            phone = tree.find(".//phoneNumber").text
            city = tree.find(".//userCity").text
            _id = tree.find(".//apppId").text
            op = tree.find(".//opType").text
            op = int(op)
            # opType
            OrderBookModel.objects.create(phone=phone, city=city, appId=_id, op_type=op, info="")
            return True
        return None

