from xml import etree

import requests

from domain.imdb.value_object import CelebrityRoleValue
from domain.lsp.base_injector import LspInjectorC2
from domain.injector.value_object import TaskStatusValue
from domain.lsp.generated.common_xsd import Adi
from imdb.models import CelebrityMediaRelationModel
from injector.models import MediaInfoSyncModel, TaskModel
from domain.lsp.value_object import CodeSampleFactory, C2ApiUtil
from utils.date_utils import datetime_now

import xml.etree.ElementTree as ET
import logging

"""
过程：
1、注入介质
2、介质回执
3、推送媒资拉取
4、lsp拉取媒资接口
5、媒资回执

工单：
1、介质注入工单
2、媒资工单
ShanXiYdGtc
"""


class ShanXiYdGtc(LspInjectorC2):
    MediaExt_Required_Args = ("media_horpic", "definition")
    Video_Required_Args = ("url", "hls_url", "definition")

    def __init__(self):
        super().__init__("SHANXIYDGTC")
        self.cp_id = self.conf.csp_id
        self.code_factory = CodeSampleFactory(self.cp_id, max_len=25)
        self.cast_sep = ";"
        self.region_sep = ";"
        self.genre_sep = ";"
        self.tag_sep = ";"
        self.username = "senyuwh"
        self.password = "TtlKKy80Ho"
        self.port = "2121"
        self.special_media = [14450, 14452, 14453]
        self.episode_num = None

    """
        P320 = 2  # 流畅 320P
    P480 = 3  # 标清 480P
    P720 = 4  # 高清 720P
    P1080 = 5  # 全高清 1080P
    P3840 = 8  # 3840x2160
    P4096 = 9  # 4096x2160
    K4 = 10  # 蓝光 4K
    """

    def gen_movie_BitId(self, storage):
        if storage.definition in (8, 9, 10):
            if storage.v_codec == "hevc":
                return 4205
            else:
                return 4104

        return storage.definition

    def movie_property(self, _id, storage, action):
        property_dict = {
            "id": _id,
            "code": _id,
            "element_type": "Movie",
            "action": action,
            "property": [
                {"FileURL": storage.hls_url},
                {"PlayURL": storage.hls_url},
                {"Dispatch": 1},
                {"Md5": storage.md5},
                {"IsTranscode": 0},
                {"MediaType": "Clear"},
                {"BitId": self.gen_movie_BitId(storage)}

            ]
        }

        return property_dict

    def gen_program_code_by_movie(self, media):
        if media.episodes == 1:
            ps_id = self.code_factory.gen_series_code(media.id)
            return ps_id
        return "暂无"

    def program_movie(self, media, storage, episode, media_ext, action):
        ps_id = self.code_factory.gen_series_code(media.id)
        series_property = self.series_property(ps_id, media, media_ext, action)
        # gitvSxcmcc660200200422425
        pp_id = self.code_factory.gen_program_code(storage.id)
        program_properties = self.program_property(pp_id, media, storage, episode, media_ext, action)
        pm_id = self.code_factory.gen_movie_code(storage.id)
        movie_property = self.movie_property(pm_id, storage, action)
        series_program_mapping = self.property_mapping("Series", "Program", ps_id, pp_id, sequence=episode.serial_num,
                                                       action=action)
        program_movie_mapping = self.property_mapping("Program", "Movie", pp_id, pm_id, action=action)

        return {
            "object_list": [series_property, program_properties, movie_property],
            "mapping_list": [series_program_mapping, program_movie_mapping]
        }

    def get_episode_num_diy(self, episode):
        if self.episode_num:
            return self.episode_num

        return episode.serial_num

    def get_episode_title_diy(self, media, episode):
        if self.episode_num:
            fmt = "{0}{1}第{2}集"
            return fmt.format(self.get_media_name_by_alias(media), " ", self.episode_num)

        return self.get_episode_title(media, episode)

    def program_property(self, _id, media, storage, 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_horpic = self.image_resize.get_oss_resize_params(self.partner_alias, media_ext.media_horpic,
                                                               size=media_ext.horpic_size, to_ip=True)
        title = self.get_episode_title_diy(media, episode)
        property_dict = {
            "element_type": "Program",
            "id": _id,
            "code": _id,
            "action": action,
            "property": [
                {"Name": title},
                {"Definition": self.gen_movie_BitId(storage)},
                {"VolumnCount": self.get_episode_num_diy(episode)},
                {"Duration": int(media.seconds)},
                {"ProgramType": self._get_category_desc_o(change_fields["category"])},
                {"IfPreview": 1},
                {"Status": 1},
                {"IsSeries": 0 if media.episodes == 1 else 1},
                {"IsCharge": change_fields["is_charge"]},
                {"PictureURL2": self.to_ip_url(media_horpic)}
            ]
        }

        return property_dict

    def program_episode(self, media, storage, episode, media_ext, action):
        ps_id = self.code_factory.gen_series_code(media.id)
        pp_id = self.code_factory.gen_program_code(storage.id)
        pm_id = self.code_factory.gen_movie_code(storage.id)
        if media.id in self.special_media:
            pp_id = self.code_factory.gen_program_code("{}e".format(storage.id))
            pm_id = self.code_factory.gen_movie_code("{}e".format(storage.id))
        program_properties = self.program_property(pp_id, media, storage, episode, media_ext, action)

        movie_properties = self.movie_property(pm_id, storage, action)
        series_program_mapping = self.property_mapping("Series", "Program", ps_id, pp_id, sequence=episode.serial_num,
                                                       action=action)
        program_movie_mapping = self.property_mapping("Program", "Movie", pp_id, pm_id, action=action)

        return {
            "object_list": [program_properties, movie_properties],
            "mapping_list": [series_program_mapping, program_movie_mapping]
        }

    def gen_series_code_by_media(self, media_id):
        ps_id = self.code_factory.gen_series_code(media_id)
        return ps_id

    def program(self, cmd_id, action):
        task_id = self.get_task_id_from_correlate_id(cmd_id)
        task = TaskModel.objects.select_related("media", "storage", "episode").filter(pk=task_id).first()
        media = task.media
        storage = task.storage
        episode = task.episode

        if media.episodes == 1:
            data = self.program_movie(media, storage, episode, media.mediaextfieldmodel, action)
        else:
            data = self.program_episode(media, storage, episode, media.mediaextfieldmodel, action)
        xml = Adi.to_xml(data, flag="None")
        return xml

    def series_property(self, _id, media, media_ext, action):
        media_verpic = self.image_resize.get_oss_resize_params(self.partner_alias, media_ext.media_verpic,
                                                               size=media_ext.verpic_size, to_ip=True)

        media_horpic = self.image_resize.get_oss_resize_params(self.partner_alias, media_ext.media_horpic,
                                                               size=media_ext.horpic_size, to_ip=True)

        param_dict = {"category": media.category, "is_charge": 1}
        change_fields = self.injected_change.get_injected_fields(media.id, self.lsp_pk, param_dict)

        _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)

        vst, vet = self.get_media_effective_time(media.id)

        property_dict = {
            "element_type": "Series",
            "id": _id,
            "code": _id,
            "action": action,
            "property": [
                {"Name": self.get_media_name_by_alias(media)},
                {"ActorDisplay": directors},
                {"PictureURL1": self.to_ip_url(media_verpic)},
                {"Description": media.storyline},
                {"ProgramType": self._get_category_desc_o(change_fields["category"])},
                {"ReleaseYear": media.year},
                {"Language": media.languages},
                {"WriterDisplay": actors},
                {"OriginalCountry": self.get_regions(media)},
                {"VolumnCount": media.episodes},
                {"Tag": self.get_genre(media)},
                {"IsCharge": change_fields["is_charge"]},
                {"HorizontalPoster": self.to_ip_url(media_horpic)},
                {"IfPreview": 1},
                {"IsSeries": 0 if media.episodes == 1 else 1},
                {"Status": 1},
                {"Definition": self.gen_series_definition(media_ext.definition)},
                {"LicensingWindowStart": vst},
                {"LicensingWindowEnd": vet},
            ]
        }
        return property_dict

    def gen_series_definition(self, definition):
        definition = int(definition)
        if definition < 5:
            return definition + 1
        elif definition == 5:
            return 4104

    def gen_album_series(self, media, media_ext, action):
        _id = self.code_factory.gen_series_code(media.id)

        series_property = self.series_property(_id, media, media_ext, action)

        return {"object_list": [series_property], "mapping_list": []}

    def album(self, cmd_id, action):
        sync_id = self.get_task_id_from_correlate_id(cmd_id)
        sync = MediaInfoSyncModel.objects.select_related("media").filter(pk=sync_id).first()
        # 工单
        media = sync.media
        media_ext = media.mediaextfieldmodel
        action = sync.action_description()
        data = self.gen_album_series(media, media_ext, action)
        # print(data)
        xml = Adi.to_xml(data, flag="Nope")
        return xml

    def exec_program_cmd(self, task, file_path):
        correct_id = self.generate_correlate_id(task.id, suffix=datetime_now())
        ftp_url = self.gen_cmd_ftp_url(file_path)
        status, msg = self.request_cms_post(correct_id, ftp_url, True)
        TaskModel.objects.filter(pk=task.id).update(status=status, remark=msg)

    def request_cms_post(self, correct_id, ftp_url, is_program=False):
        try:
            xml_data = C2ApiUtil.REQUESTXML.format(self.cp_id, self.conf.lsp_id, correct_id, ftp_url)
            print(xml_data)
            logging.warning(xml_data)
            headers = {"Content-Type": "text/json", "SOAPAction": "application/soap+xml;charset=utf8"}
            content = requests.post(self.conf.cms_api, headers=headers, data=xml_data).content
            print(content)
            logging.warning(content)
            tree = ET.fromstring(content)
            code = tree.find(".//Result").text
            msg = tree.find(".//ErrorDescription").text
        except Exception as e:
            logging.error(e)
            code = -1
            msg = str(e)
        if code == "0":
            status = MediaInfoSyncModel.SYNCING
            msg = ""
            if is_program: status = TaskStatusValue.INFO_TRANSFERING
        else:
            status = MediaInfoSyncModel.FAILED
            if is_program: status = TaskStatusValue.INFO_FAILED
        return status, msg

    def exec_sync_header_cmd(self, sync, file_path):
        correct_id = self.generate_correlate_id(sync.id, "series", datetime_now())
        ftp_url = self.gen_cmd_ftp_url(file_path)
        status, msg = self.request_cms_post(correct_id, ftp_url)
        MediaInfoSyncModel.objects.filter(pk=sync.id).update(status=status, remark=msg)

    def gen_cmd_ftp_url(self, xml_url):
        ftp_url = "ftp://{}:{}@{}:{}/{}".format(
            self.username, self.password, self.HOST, self.port, xml_url
        )
        return ftp_url

    def injector(self, task, action="REGIST", num=None):
        self.episode_num = num
        status, flag = 0, 0
        if task.status in (TaskStatusValue.FILE_PENDING, TaskStatusValue.INFO_PENDING):
            # 生成表示码
            task_id = self.generate_correlate_id(task.id)
            # 生成工单
            file_path = self.save_album_xml_file(self.cp_id, task_id, "program", action=action)
            # 执行注入
            status = self.exec_program_cmd(task, file_path)
            flag = self.get_continue_to_injector(status)
        self.episode_num = None
        return status, flag

    def series_header_injector(self, msync, action="REGIST"):
        if msync.status == MediaInfoSyncModel.PENDING:
            # 生成表示码
            sync_id = self.generate_correlate_id(msync.id, stage="series")
            # 生成工单
            file_path = self.save_album_xml_file(self.cp_id, sync_id, action=action)
            # 执行注入
            self.exec_sync_header_cmd(msync, file_path)

    def series_header_remove(self, sync):
        self.series_header_injector(sync)

    def series_header_update(self, sync):
        self.series_header_injector(sync)

    def remove(self, task):
        self.injector(task, action="DELETE")
        self.off_line_storage(task.partner_id, task.storage_id)

    def update(self, task):
        self.injector(task, action="UPDATE")
        self.update_storage(task.partner_id, task.storage_id)

    def callback_audit(self, list_data):
        for program_item in list_data:
            # gitvSxcmcc660200200422425
            content_id = program_item.get("contentId")
            result = program_item.get("downloadResult")
            msg = program_item.get("downloadMsg")
            csp_id = program_item.get("cspId")
            s_id_str = content_id.replace("gitvSxcmcc6602002", "")
            storage_id = int(s_id_str.strip())
            logging.warning("lsp:{} storage:{} cdn上传回调".format(self.lsp_pk, storage_id))
            TaskModel.objects.filter(partner_id=self.lsp_pk, storage_id=storage_id).update(remark=msg)
        result = {"code": "0", "message": "成功"}
        return result
