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, DefinitionValue
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
import re

"""
过程：
1、注入介质
2、介质回执
3、推送媒资拉取
4、lsp拉取媒资接口
5、媒资回执

工单：
1、介质注入工单
2、媒资工单
ShanXiYdGtc
"""


class YunNanYiDong(LspInjectorC2):
    MediaExt_Required_Args = ("media_horpic", "approval_num")

    def __init__(self):
        super().__init__("YUNNANYIDONG")
        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.prefix = "（来源森宇文化）"
        self.only_id = ["2139"]

    """
        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 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_storage_type(self, content_type):
        if content_type != 1:
            return 2
        return content_type

    def get_aspect(self, display_aspect_ratio):
        if "16:9" in display_aspect_ratio:
            return 1
        return 0

    def gen_definition(self, definition):
        if definition == DefinitionValue.P720:
            return "720P"

        if definition == DefinitionValue.P1080:
            return "1080i"
        if definition == DefinitionValue.P3840:
            return "3840i"

        if definition in (DefinitionValue.P4096, DefinitionValue.K4):
            return "4096i"

        return "576i"

    def gen_audio_bit(self, a_bit):
        if a_bit - 50 < 100:
            return 128
        elif a_bit > 200:
            return a_bit
        else:
            return 192

    def gen_media_spec(self, storage):
        # TS-CBR-H264-2048-576i-25-AAC-100
        _p1 = "TS"
        _p2 = "CBR"
        _p3 = "H264" if storage.v_codec == "h264" else "HEVC"
        _p4 = storage.v_bit_rate // 1000
        _p5 = self.gen_definition(storage.definition)
        _p6 = storage.frame_rate if storage.frame_rate else "25"
        _p7 = "AAC" if storage.a_codec.lower() == "aac" else "MP2"
        _p8 = self.gen_audio_bit(storage.a_bit_rate // 1000)

        return "{}-{}-{}-{}-{}-{}-{}-{}".format(_p1, _p2, _p3, _p4, _p5, _p6, _p7, _p8)
        # return "TS-CBR-H.264-1080i-AAC"

    def movie_property(self, _id, storage, action):
        property_dict = {
            "id": _id,
            "code": _id,
            "element_type": "Movie",
            "action": action,
            "property": [
                {"FileURL": self.get_storage_ftp_url(storage.url)},
                {"Type": self.gen_storage_type(storage.content_type)},
                {"ScreenFormat": self.get_aspect(storage.display_aspect_ratio)},
                {"ClosedCaptioning": 1},
                {"MediaSpec": self.gen_media_spec(storage)},

            ]
        }

        return property_dict

    def program_movie(self, media, storage, episode, media_ext, action):
        pp_id = self.code_factory.gen_series_code(media.id)
        program_properties = self.program_property_movie(pp_id, media, media_ext, action)
        pm_id = self.code_factory.gen_movie_code(storage.id)
        movie_property = self.movie_property(pm_id, storage, action)

        p_hor_id = self.code_factory.gen_media_hpic_code(media.id)
        p_ver_id = self.code_factory.gen_media_vpic_code(media.id)

        media_verpic = media_ext.media_verpic
        media_horpic = media_ext.media_horpic

        size_verpic = self.image_resize.YUNNANYIDONG.get("verpic")
        size_horpic = self.image_resize.YUNNANYIDONG.get("horpic")

        hor_picture = self.property_picture(p_hor_id, media_horpic, size_horpic, action)
        ver_picture = self.property_picture(p_ver_id, media_verpic, size_verpic, action)

        hor_mapping = self.property_mapping("Picture", "Program", p_hor_id, pp_id, _type=2, sequence=2,
                                            action=action)
        ver_mapping = self.property_mapping("Picture", "Program", p_ver_id, pp_id, _type=1, sequence=1,
                                            action=action)

        program_movie_mapping = self.property_mapping("Program", "Movie", pp_id, pm_id, _type="", sequence=1,
                                                      action=action)

        return {
            "BizDomain": "2",
            "object_list": [program_properties, movie_property, hor_picture, ver_picture],
            "mapping_list": [program_movie_mapping, hor_mapping, ver_mapping]
        }

    def get_episode_title(self, media, episode):
        title = "{}[{}]".format(self.get_media_name_by_alias(media), episode.serial_num)
        return title

    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)
        title = self.get_episode_title(media, episode)
        search_name = self.transform_chinese_to_letter(self.get_media_name_by_alias(media))

        _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": "Program",
            "id": _id,
            "code": _id,
            "action": action,
            "property": [
                {"Name": title},
                {"OriginalName": title},
                {"SortName": search_name},
                {"SearchName": search_name},
                # {"Definition": self.gen_movie_BitId(storage)},
                {"VolumnCount": media.episodes},
                {"Duration1": int(media.seconds)},
                {"ProgramType": self._get_category_desc(change_fields["category"])},
                {"ProgramType2": self.get_genre(media)},
                {"ActorDisplay": actors},
                {"WriterDisplay": writers},
                {"OriginalCountry": self.get_regions(media)},
                {"Caption_Language": self.gen_caption_Language(media.languages)},
                {"Language": media.languages},
                {"Description": self.prefix + media.storyline},
                {"ContentLisence": media_ext.approval_num},
                {"ContentProvider": self.conf.csp_name},
                {"Status": 1},
                {"SourceType": 1},
                {"SeriesFlag": 1},
                {"Kpeople": actors},
                {"Director": directors},
                {"ReleaseYear": media.year},
                {"LicensingWindowStart": vst},
                {"LicensingWindowEnd": vet},
                {"StartTime": episode.begin},
                {"EndTime": episode.end}
            ]
        }

        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)
        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 {
            "BizDomain": "2",
            "object_list": [program_properties, movie_properties],
            "mapping_list": [series_program_mapping, program_movie_mapping]
        }

    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 program_property_movie(self, _id, media, 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)

        _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)
        search_name = self.transform_chinese_to_letter(self.get_media_name_by_alias(media))
        property_dict = {
            "element_type": "Program",
            "id": _id,
            "code": _id,
            "action": action,
            "property": [
                {"Name": self.get_media_name_by_alias(media)},
                {"Kpeople": actors},
                {"OriginalName": self.get_media_name_by_alias(media)},
                {"SortName": search_name},
                {"SearchName": search_name},
                {"ActorDisplay": actors},
                {"Director": directors},
                {"Description": self.prefix + media.storyline},
                {"ReleaseYear": media.year},
                {"Language": media.languages},
                {"OriginalCountry": self.get_regions(media)},
                {"VolumnCount": media.episodes},
                {"Status": 1},
                {"SourceType": 1},
                {"SeriesFlag": 0},
                {"ContentProvider": self.conf.csp_name},
                {"ProgramType": self._get_category_desc(change_fields["category"])},
                {"ProgramType2": self.get_genre(media)},
                {"Genre": self._get_category_desc(change_fields["category"])},
                {"AssetTag": self.get_genre(media)},
                {"Keywords": self.get_genre(media)},
                {"Caption_Language": media.languages},
                {"ContentLisence": media_ext.approval_num},
                {"Summary_Short": media_ext.focus},
                {"LicensingWindowStart": vst},
                {"LicensingWindowEnd": vet},
            ]
        }
        return property_dict

    def gen_caption_Language(self, language):
        if language == "英语":
            return "英文"
        return "中文"

    def series_property(self, _id, media, 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)

        _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)
        search_name = self.transform_chinese_to_letter(self.get_media_name_by_alias(media))
        property_dict = {
            "element_type": "Series",
            "id": _id,
            "code": _id,
            "action": action,
            "property": [
                {"Name": self.get_media_name_by_alias(media)},
                {"OriginalName": self.get_media_name_by_alias(media)},
                {"SortName": search_name},
                {"SearchName": search_name},
                {"ActorDisplay": actors},
                {"Kpeople": actors},
                {"Director": directors},
                {"Description": self.prefix + media.storyline},
                {"ReleaseYear": media.year},
                {"Language": media.languages},
                {"OriginalCountry": self.get_regions(media)},
                {"VolumnCount": media.episodes},
                {"Status": 1},
                {"SeriesType": 0},
                {"ContentProvider": self.conf.csp_name},
                {"PgmCategory": self._get_category_desc(change_fields["category"])},
                {"PgmSndClass": self.get_genre(media)},
                {"ProgramType": self._get_category_desc(change_fields["category"])},
                {"ProgramType2": self.get_genre(media)},
                {"Genre": self._get_category_desc(change_fields["category"])},
                {"AssetTag": self.get_genre(media)},
                {"Tags": self.get_genre(media)},
                {"Caption_Language": self.gen_caption_Language(media.languages)},
                {"Summary_Short": media_ext.focus},
                {"ContentLisence": media_ext.approval_num},
                {"LicensingWindowStart": vst},
                {"LicensingWindowEnd": vet},
            ]
        }
        return property_dict

    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 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)

        p_hor_id = self.code_factory.gen_media_hpic_code(media.id)
        p_ver_id = self.code_factory.gen_media_vpic_code(media.id)

        media_verpic = media_ext.media_verpic
        media_horpic = media_ext.media_horpic

        size_verpic = self.image_resize.YUNNANYIDONG.get("verpic")
        size_horpic = self.image_resize.YUNNANYIDONG.get("horpic")

        series_property = self.series_property(_id, media, media_ext, action)

        hor_picture = self.property_picture(p_hor_id, media_horpic, size_horpic, action)
        ver_picture = self.property_picture(p_ver_id, media_verpic, size_verpic, action)

        hor_mapping = self.property_mapping("Picture", "Series", p_hor_id, _id, _type=2,
                                            action=action)
        ver_mapping = self.property_mapping("Picture", "Series", p_ver_id, _id, _type=1,
                                            action=action)

        return {
            "BizDomain": "2",
            "object_list": [series_property, hor_picture, ver_picture],
            "mapping_list": [hor_mapping, ver_mapping]
        }

    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"):
        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)
        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)
