import logging
import random

import requests
import xml.etree.ElementTree as ET

from domain import domain_except
from domain.imdb.value_object import CelebrityRoleValue
from domain.lsp.generated.common_xsd import Adi
from domain.lsp.value_object import CodeSampleFactory, C2ApiUtil
from imdb.models import CelebrityMediaRelationModel
from injector.models import MediaInfoSyncModel, TaskModel, MediaExtFieldModel
from .base_injector import LspInjectorC2
from domain.injector.value_object import TaskStatusValue, DefinitionValue, ContentTypeValue
from domain.imdb.value_object import CategoryValue

from utils.date_utils import datetime_now

logger = logging.getLogger(__file__)


class XinJiangTv(LspInjectorC2):
    MediaExt_Required_Args = ("media_horpic", "approval_num", "copyright")
    Key_Remark = {"approval_num": "审批号", "copyright": "上游版权方"}

    def __init__(self, alias="XINJIANGTV"):
        super().__init__(alias)
        self.lsp_id = self.conf.lsp_id
        self.csp_id = self.conf.csp_id
        self.cms_api = self.conf.cms_api
        self.csp_name = self.conf.csp_name
        self.cast_sep = ","
        self.region_sep = ","
        self.genre_sep = ","
        self.tag_sep = ","
        self.code_factory = CodeSampleFactory(self.csp_id)
        self.desc_prefix = "(来源于森宇)"
        self.type_num_mapper = {"H.264": 1, "MPEG4": 2, "AVS": 3, "MPEG2": 4, "MP3": 5, "H.265": 7, "AVS2": 8}
        self.resolution_num_mapper = {"QCIF": 1, "QVGA": 2, "2/3 D1": 3, "3/4 D1": 4, "D1": 5, "720P": 6, "1080i": 7,
                                      "1080P": 8, "4K(3840*2160)": 9, "4K(4096*2160)": 10}
        self.is_telecom = False

    def check_module_args(self, model, keys):
        for key in keys:
            value = getattr(model, key)
            if not value:
                key_s = self.Key_Remark.get(key) or key
                raise domain_except.ParamRequiredException("缺少必填参数:{}".format(key_s))

    # 会在剧头注入创建前 调用该检测方法
    def check_series_header_args(self, media_id):
        media_ext = MediaExtFieldModel.objects.get(media_id=media_id)
        self.check_module_args(media_ext, self.MediaExt_Required_Args)
        return

    def get_stbld_nums(self):
        the_num = TaskModel.objects.filter(partner_id=self.lsp_pk).count()
        if len(str(the_num)) <= 5:
            return str(the_num).rjust(5, "0")
        elif len(str(the_num)) <= 7:
            return str(the_num).rjust(7, "0")
        else:
            return "{}{}".format(random.randint(10, 99), str(the_num)[-5:])

    def get_content_type(self, content_type):
        return {
            ContentTypeValue.POSITIVE: "正片",
            ContentTypeValue.CLIP: "花絮",
            ContentTypeValue.TRAILER: "预告片"
        }.get(content_type, "正片")

    # 清晰度（1:高清HD、2:流畅LD、3:标清SD、4：XD，默认SD）
    def _get_bit_rate_type(self, definition):
        if definition == DefinitionValue.P320:
            return "LD"
        elif definition == DefinitionValue.P480:
            return "SD"
        elif definition == DefinitionValue.P720:
            return "HD"
        elif definition == DefinitionValue.P1080:
            return "XD"
        elif definition == DefinitionValue.K4:
            return "XD"
        return "SD"

    def _get_video_type(self, type):

        type_mapper = {"h264": "H.264", "hevc": "H.265", "mpeg4": "MPEG4", "mpeg2": "MPEG2", "avs": "AVS",
                       "avs2": "AVS2"}

        return self.type_num_mapper[type_mapper[type]]

    def _get_resolution(self, definition, width):
        def_mapper = {DefinitionValue.P320: "2/3 D1", DefinitionValue.P480: "D1", DefinitionValue.P720: "720P",
                      DefinitionValue.P1080: "1080P",
                      DefinitionValue.K4: "4K(3840*2160)" if width == 3840 else "4K(4096*2160)"}
        return self.resolution_num_mapper[def_mapper[definition]]

    def get_tags(self, media_obj):
        genres = media_obj.genres
        if genres and len(genres):
            names = [genre["name"] for genre in genres]
            return self.tag_sep.join(names)
        return ""

    def change_cast(self, casts, playplat):
        if not casts or "佚名" == casts:
            return playplat
        return casts

    def get_telecom(self, telecom, category):
        r = []
        if self.is_telecom:
            if category in (CategoryValue.CHILDREN, CategoryValue.EDUCATION):
                r.append("电信")
            elif category in (CategoryValue.MOVIE, CategoryValue.TVSERIES):
                r.append("联通")
            r = ",".join(r)
        else:
            if "移动" in telecom:
                r.append("移动")
            if category in (CategoryValue.CHILDREN, CategoryValue.EDUCATION, CategoryValue.TVSERIES, CategoryValue.MOVIE, CategoryValue.ANIMATION):
                if "联通" in telecom:
                    r.append("联通")
                if "电信" in telecom:
                    r.append("电信")
            elif category == CategoryValue.VARIETY:
                if "联通" in telecom:
                    r.append("联通")
                if "电信" in telecom:
                    r.append("电信")
            r = ",".join(r)
            if len(r) == 0:
                r = "移动"

        return r

    def property_series(self, ps_id, media, media_ext, action="REGIST"):
        _actors = CelebrityMediaRelationModel.objects.filter(
            media_id=media.id, role=CelebrityRoleValue.ACTOR).select_related("celebrity")[:4]
        _directors = CelebrityMediaRelationModel.objects.filter(
            media_id=media.id, role=CelebrityRoleValue.DIRECTOR).select_related("celebrity")[:4]
        _writers = CelebrityMediaRelationModel.objects.filter(
            media_id=media.id, role=CelebrityRoleValue.AUTHOR).select_related("celebrity")[:2]
        actors, directors, writers = self.join_names(_actors), self.join_names(_directors), self.join_names(
            _writers)
        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)

        the_property = [
            {"Director": self.change_cast(directors, media_ext.playplat)},  # 要写导演 一会改动
            {"Status": 1},
            {"Name": self.get_media_name_by_alias(media)},
            {"SearchName": self.transform_chinese_to_letter(self.get_media_name_by_alias(media))},
            {"Language": media.languages},
            {"Kpeople": self.change_cast(actors, media_ext.playplat)},  # 这里是主演
            {"Description": self.make_desc_prefix(media.storyline)},
            {"Type": self._get_category_desc(change_fields["category"])},
            {"Tags": self.get_genre(media)},
            {"ReleaseYear": media.year},
            {"VolumnCount": media.episodes},
            {"OrgAirDate": "".join(media.date_published.split("-"))},
            {"OriginalCountry": self.get_regions(media)},
            {"Score": media.douban_score},
            {"Duration": int(media.total_seconds / 60) + 1},
            {"LicensingWindowStart": vst},
            {"LicensingWindowEnd": vet},
            {"Approval": media_ext.approval_num},
            {"SPCode": self.get_telecom(media_ext.telecom, change_fields["category"])},
            {"CopyRight": media_ext.copyright},
            {"ContentProvider": self.csp_name}
        ]
        return {
            "element_type": "Series",
            "id": ps_id,
            "code": ps_id,
            "action": action,
            "property": the_property
        }

    # 要求简介 有前缀
    def make_desc_prefix(self, content):
        return self.desc_prefix + content

    # 只支持一个国家 目前处理是取第一个国家
    def get_regions(self, media_obj):
        regions = media_obj.regions
        if regions and len(regions):
            names = [region["name"] for region in regions]
            # 目前个别平台 需要改成内地，先分开处理,平台统一后在 统一处理
            if names[0] == "中国大陆":
                return "内地"
            return names[0]
        return ""

    def filter_cast(self, casts):
        pass

    def property_picture(self, _id, url, action="REGIST"):

        return {
            "element_type": "Picture",
            "id": _id,
            "code": _id,
            "action": action,
            "property": [
                {"FileURL": self.to_ip_url(url)},
            ]
        }

    # 定义剧头信息
    def _album_series_header(self, media, media_ext, info_sync):
        # 定义ID、Action、Code
        action = info_sync.action_description()
        if action == "UPDATE":
            action = "REGIST"
        # 获取必要信息
        media_verpic = self.image_resize.get_oss_resize_params(self.partner_alias, media_ext.media_verpic,
                                                               size=media_ext.verpic_size, to_ip=True)
        ps_id = self.code_factory.gen_series_code(media.id)
        ps_ver_pic_id = self.code_factory.gen_media_vpic_code(media.id)
        p_series = self.property_series(ps_id, media, media_ext, action)
        p_picture = self.property_picture(ps_ver_pic_id, media_verpic)

        mapping_series_ver_picture = self.property_mapping("Picture", "Series", ps_ver_pic_id, ps_id, _type=1,
                                                           sequence=1,
                                                           action=action)
        return {
            "object_list": [p_series, p_picture],
            "mapping_list": [mapping_series_ver_picture]
        }

    # 定义剧头xml信息
    def album(self, _task_id, action="REGIST"):

        # 获取taskId
        task_id = str(_task_id).split("_")[0]

        # 从MediaInfo中获取media信息
        info_sync = MediaInfoSyncModel.objects.filter(pk=task_id).select_related("media").first()
        media = info_sync.media
        media_ext = media.mediaextfieldmodel

        data = self._album_series_header(media, media_ext, info_sync)
        logger.warning(data)
        xml = Adi.to_xml(data, flag="Nope")
        logger.warning(xml)
        return xml

    def property_movie(self, _id, media_storage, _type=1, action="REGIST"):
        return {
            "element_type": "Movie",
            "id": _id,
            "code": _id,
            "action": action,
            "property": [
                {"Code": _id},
                {"FileURL": self.change_storage_url(media_storage.url)},
                {"Type": _type}
            ]
        }

    # 定义分集信息
    def _album_sub_series(self, media_storage, media, episode, media_ext, _episodes, action="REGIST"):

        # 还需要添加媒资信息
        actors, directors, writers = self.get_media_person(media, actor=4, director=4, writer=2)
        vst, vet = self.get_media_effective_time(media.id)
        param_dict = {"category": media.category, "is_charge": 1}
        pmid = self.code_factory.gen_movie_code(media_storage.id)
        psid = self.code_factory.gen_series_code(media.id)
        episode_title = self.get_episode_title(media, episode)
        param_dict = {"category": media.category, "is_charge": 1}
        change_fields = self.injected_change.get_injected_fields(media.id, self.lsp_pk, param_dict)

        ppid = self.code_factory.gen_program_code(media_storage.id)

        # 定义 program 对象部分
        p_program = {
            "element_type": "Program",
            "id": ppid,
            "code": ppid,
            "action": action,
            "property": [
                {"Code": ppid},
                {"Name": episode_title},
                {"Description": self.make_desc_prefix(media.storyline)},
                {"SourceType": 1},
                {"Status": 1},
                {"SeriesFlag": 1},
                {"Kpeople": self.change_cast(actors, media_ext.playplat)},
                {"Director": self.change_cast(directors, media_ext.playplat)},
                {"LicensingWindowStart": vst},
                {"LicensingWindowEnd": vet},
                {"Duration": int(media_storage.seconds / 60) + 1},
                {"Type": self._get_category_desc(change_fields["category"])},
                {"OriginalCountry": self.get_regions(media)},
            ]
        }

        p_movie = self.property_movie(pmid, media_storage, action=action)
        mapping_program = self.property_mapping("Series", "Program", psid, ppid, sequence=episode.serial_num,
                                                action=action)
        mapping_movie = self.property_mapping("Program", "Movie", ppid, pmid, action=action)

        return {
            "object_list": [p_program, p_movie],
            "mapping_list": [mapping_program, mapping_movie]
        }

    def property_program(self, _id, media_ext, media, action="REGIST"):
        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)
        param_dict = {"category": media.category, "is_charge": 1}
        change_fields = self.injected_change.get_injected_fields(media.id, self.lsp_pk, param_dict)
        return {
            "element_type": "Program",
            "id": _id,
            "code": _id,
            "action": action,
            "property": [
                {"Director": self.change_cast(directors, media_ext.playplat)},  # 要写导演 一会改动
                {"SourceType": 1},
                {"Status": 1},
                {"SeriesFlag": 0},
                {"SourceType": 1},
                {"Name": self.get_media_name_by_alias(media)},
                {"SearchName": self.transform_chinese_to_letter(self.get_media_name_by_alias(media))},
                {"Language": media.languages},
                {"ActorDisplay": self.change_cast(actors, media_ext.playplat)},
                {"Kpeople": self.change_cast(actors, media_ext.playplat)},  # 这里是主演
                {"Description": self.make_desc_prefix(media.storyline)},
                {"Type": self._get_category_desc(change_fields["category"])},
                {"Tags": self.get_genre(media)},
                {"ReleaseYear": media.year},
                {"OrgAirDate": "".join(media.date_published.split("-"))},
                {"OriginalCountry": self.get_regions(media)},
                {"Score": media.douban_score},
                {"Duration": int(media.total_seconds / 60) + 1},
                {"LicensingWindowStart": vst},
                {"LicensingWindowEnd": vet},
                {"Approval": media_ext.approval_num},
                {"SPCode": self.get_telecom(media_ext.telecom, change_fields["category"])},
                {"CopyRight": media_ext.copyright},
                {"ContentProvider": self.csp_name}
            ]
        }

    # 定义电影
    def _album_movie(self, media_storage, media, episode, 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_ext = media.mediaextfieldmodel
        ppid = self.code_factory.gen_program_code(media_storage.id)
        pmid = self.code_factory.gen_movie_code(media_storage.id)
        ver_pic_id = self.code_factory.gen_media_vpic_code(media.id)

        p_program = self.property_program(ppid, media_ext, media, action)

        p_picture = self.property_picture(ver_pic_id, media_verpic)
        p_movie = self.property_movie(pmid, media_storage, action=action)

        mapping_movie = self.property_mapping("Program", "Movie", ppid, pmid, action=action)

        mapping_ver_picture = self.property_mapping("Picture", "Program", ver_pic_id, ppid, _type=1,
                                                    sequence=1,
                                                    action=action)

        return {
            "object_list": [p_program, p_movie, p_picture],
            "mapping_list": [mapping_movie, mapping_ver_picture]
        }

    # 定义节目xml信息
    def program(self, _task_id, action="REGIST"):
        task_id, _ = _task_id.split("_", 1)
        task = TaskModel.objects.filter(pk=task_id).select_related("storage").first()
        media_storage = task.storage  # 媒介
        media = media_storage.media  # 媒体文件主体
        episode = media_storage.episode  # (分集)扩展信息
        media_ext = media.mediaextfieldmodel  # 媒体文件补充信息

        # 目前的设计是 任何媒介都要有1集  电影也要设置为1集
        _episodes = int(media.episodes) if media.episodes else 0
        if _episodes > 1:  # 如果大于1 表示 连续剧 则该介质是某集电视剧
            data = self._album_sub_series(media_storage, media, episode, media_ext, _episodes, action)
        else:  # 电影
            data = self._album_movie(media_storage, media, episode, media_ext, action)
        xml = Adi.to_xml(data, flag="Nope")
        logger.warning(xml)
        return xml

    # 剧头注入  向LSP发起xml内容
    def exec_sync_header_cmd(self, sync, count=0):
        count += 1
        _sync_id = self.generate_correlate_id(sync.id, stage="series")
        cmd_file_url = self.get_cmd_ftp_url(self.csp_id, _sync_id)
        sync_id = "{}_{}".format(_sync_id, datetime_now())
        xml = C2ApiUtil.REQUESTXML.format(self.csp_id, self.lsp_id, sync_id, cmd_file_url)
        logger.warning("{} exec_sync_header_cmd HEADER_ID: {}, Request: {}".format(self.lsp_id, sync.id, xml))
        headers = {"content-type": "text/xml", "SOAPAction": "application/soap+xml;charset=utf8"}
        response = requests.post(self.cms_api, data=xml, headers=headers).content
        logger.warning("{} exec_sync_header_cmd HEADER_ID: {}, Response: {}".format(self.lsp_id, sync.id, response))
        tree = ET.fromstring(response)
        msg = tree.find(".//ErrorDescription").text
        if msg.lower() == "success":
            status = MediaInfoSyncModel.SYNCING
        else:
            if str(msg).lower().__contains__("could not connect") and count < self.try_count:
                return self.exec_sync_header_cmd(sync, count)
            status = MediaInfoSyncModel.FAILED
        the_sync = MediaInfoSyncModel.objects.filter(pk=sync.id).first()
        if the_sync.status == MediaInfoSyncModel.PENDING:
            the_sync.status = status
            the_sync.remark = msg
            the_sync.save()

        return

    # 剧头注入处理
    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)
        return

    # 介质注入 向LSP发起xml内容
    def exec_cmd(self, task_id, count=0):
        count += 1
        _task_id = self.generate_correlate_id(task_id)
        cmdfileUrl = self.get_cmd_ftp_url(self.csp_id, _task_id)  # ftp协议
        xml = C2ApiUtil.REQUESTXML.format(self.csp_id, self.lsp_id, "{}_{}".format(_task_id, datetime_now()),
                                          cmdfileUrl)
        logger.warning("EXEC_CMD Request: {}".format(xml))
        headers = {"content-type": "text/xml", "SOAPAction": "application/soap+xml;charset=utf8"}
        response = requests.post(self.cms_api, data=xml, headers=headers).content
        logger.warning("EXEC_CMD Response: {}".format(response))
        tree = ET.fromstring(response)
        # code = tree.find(".//Result").text
        msg = tree.find(".//ErrorDescription").text

        if msg.lower() == "success":
            status = TaskStatusValue.FILE_TRANSFERING
            remark = ""
        else:
            if str(msg).lower().__contains__("could not connect") and count < self.try_count:
                return self.exec_cmd(task_id, count)
            status = TaskStatusValue.FILE_FAILED
            remark = msg

        TaskModel.objects.filter(pk=task_id).update(status=status, remark=remark)
        return status

    # 介质注入
    def injector(self, task):
        status, flag = 0, 0
        # 如果工单状态 在 pending 在就绪状态，我们就继续
        if task.status in (TaskStatusValue.FILE_PENDING, TaskStatusValue.INFO_PENDING):
            # 组成一新的task_id  在全局中唯一 taskId_00
            _task_id = self.generate_correlate_id(task.id)
            # 生成新的xml
            self.save_album_xml_file(self.csp_id, _task_id, param="program")
            status = self.exec_cmd(task.id)
            flag = self.get_continue_to_injector(status)
        return status, flag

    # 介质注入更新
    def update(self, task):
        if task.status in (TaskStatusValue.FILE_PENDING, TaskStatusValue.INFO_PENDING):
            _task_id = self.generate_correlate_id(task.id)
            self.save_album_xml_file(self.csp_id, _task_id, param="program")
            self.exec_cmd(task.id)

    # 介质注入删除
    def remove(self, task):
        if task.status in (TaskStatusValue.FILE_PENDING, TaskStatusValue.INFO_PENDING):
            _task_id = self.generate_correlate_id(task.id)
            self.save_album_xml_file(self.csp_id, _task_id, param="program", action="DELETE")
            self.exec_cmd(task.id)
            self.off_line_storage(task.partner_id, task.storage_id)
            logger.warning("{} 下线媒体: {}, task_id: {}".format(self.partner_alias, task.storage_id, task.id))

    # 更新 剧头
    def series_header_update(self, sync):
        self.series_header_injector(sync)

    # 删除 剧头  目前新疆IPTV 没有给cp 删除权限  执行了不会起作用
    def series_header_remove(self, sync):
        self.series_header_injector(sync)
