import logging
import requests

from lxml import etree
from injector.models import TaskModel
from injector.models import MediaInfoSyncModel
from domain.lsp.generated.common_xsd import Adi
from domain.lsp.base_injector import LspInjectorC2
from domain.lsp.value_object import C2ApiUtil, CodeFactory
from domain.injector.value_object import TaskStatusValue
from domain.imdb.value_object import CategoryValue

from utils.date_utils import datetime_now

logger = logging.getLogger(__file__)


# 多个匹配结果(只针对两层，一层空一层真正)返回code
def return_code(codes):
    code = -1
    for c in codes:
        try:
            if int(c.text) != code:
                code = int(c.text)
        except TypeError:
            pass
        except ValueError:
            if c.text == "Success" or c.text == "success":
                code = 0
    return code


class ShanXiPukka(LspInjectorC2):

    def __init__(self, alias="shanxiPukka"):
        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.desc_prefix1 = "【内容来源森宇】"
        self.desc_prefix2 = "【来源于森宇少儿】"
        self.desc_suffix2 = "@@@SYSE"

    def property_program(self, category, _id, name, media, action="REGIST"):
        search_name = self.transform_chinese_to_letter(name.replace(" ", ""))
        return {
            "element_type": "Program",
            "id": _id,
            "code": _id,
            "action": action,
            "property": [
                {"Name": name},
                {"SearchName": search_name},
                {"OrgAirDate": media.date_published},
                {"Keywords": search_name},
                {"Tags": self.get_genre(media)},
                {"VolumnCount": media.episodes},
                {"Description": self.make_desc_prefix(category, media.storyline)},
                {"Status": 1},
                {"Duration": int(media.seconds / 60) + 1},
                {"Language": media.languages},
                {"ReleaseYear": media.year},
                {"OriginalCountry": self.get_regions(media)},
                {"ContentProvider": self.csp_name},  # 内容提供商
            ]
        }

    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": media_storage.url},
                {"AudioType": self.get_audio_type(media_storage.a_codec)},
                {"BitRateType": self._get_bit_rate_type(media_storage.definition)},
            ]
        }

    def property_series(self, category, _id, volumn_count, media, action="REGIST"):
        search_name = self.transform_chinese_to_letter(self.get_media_name_by_alias(media))
        the_property = [
            {"Name": self.get_media_name_by_alias(media)},
            {"OrgAirDate": media.date_published},
            {"Keywords": search_name},
            {"Tags": self.get_genre(media)},
            {"KindDisplay": self.get_genre(media)},
            {"VolumnCount": volumn_count},
            {"Status": 1},
            {"Description": self.make_desc_prefix(category, media.storyline)},
            {"Duration": int(media.total_seconds / 60) + 1},
            {"Language": media.languages},
            {"ReleaseYear": media.year},
            {"OriginalCountry": self.get_regions(media)},
            {"ContentProvider": self.csp_name},
            {"SearchName": search_name},
        ]
        return {
            "element_type": "Series",
            "id": _id,
            "code": _id,
            "action": action,
            "property": the_property
        }

    # 陕西IPTV 简介内容 前后缀修改
    def make_desc_prefix(self, category, content):
        if category == CategoryValue.CHILDREN:
            return self.desc_prefix2 + content + self.desc_suffix2

        elif category in (CategoryValue.MOVIE, CategoryValue.TVSERIES):
            return self.desc_prefix1 + content

        return content

    def property_picture(self, _id, file_url, _type=1, action="REGIST"):
        return {
            "element_type": "Picture",
            "id": _id,
            "code": _id,
            "action": action,
            "property": [
                {"Type": _type},
                {"FileURL": self.to_ip_url(file_url)},
            ]
        }

    # 有分集标题时
    def _have_episode_title(self, media, episode):
        fmt = "{0}{1}第{2}集"
        return fmt.format(self.get_media_name_by_alias(media), " ", episode.serial_num)

    def _album_movie(self, media_storage, media, episode, media_ext, action="REGIST"):
        actors, directors, writers = self.get_media_person(media, actor=4, director=4, writer=2)
        vst, vet = self.get_episode_effective_time(media.id, episode.serial_num)
        param_dict = {"category": media.category}
        category = self.injected_change.get_injected_fields(media.id, self.lsp_pk, param_dict)["category"]

        ppid = self.code_factory.gen_program_code(media.id)
        p_program = self.property_program(category, ppid, self.get_media_name_by_alias(media), media, action=action)
        p_program["property"].extend([
            {"ActorDisplay": actors},
            {"Director": directors},
            {"ScriptWriter": writers},
            {"Type": self._get_category_desc(category)},
            {"LicensingWindowStart": vst},
            {"LicensingWindowEnd": vet},
            {"SourceType": 1},
            {"SeriesFlag": 0},
            {"Isfree": 2},
        ])

        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)

        pmpid = self.code_factory.gen_media_vpic_code(episode.id)
        media_verpic = self.image_resize.get_oss_resize_params(self.partner_alias, media_ext.media_verpic,
                                                               size=media_ext.verpic_size, to_ip=True,
                                                               category=self._get_category_desc(category))
        p_program_picture = self.property_picture(pmpid, media_verpic, action=action)
        mapping_program_picture = self.property_mapping("Picture", "Program", pmpid, ppid, sequence=0, action=action)
        return {
            "object_list": [p_program, p_movie, p_program_picture],
            "mapping_list": [mapping_movie, mapping_program_picture]
        }

    def _album_series_header(self, media, media_ext, info_sync):
        action = info_sync.action_description()
        _episodes = int(media.episodes) if media.episodes else 0
        vst, vet = self.get_media_effective_time(media.id)
        actors, directors, writers = self.get_media_person(media, actor=4, director=4, writer=2)
        param_dict = {"category": media.category}
        category = self.injected_change.get_injected_fields(media.id, self.lsp_pk, param_dict)["category"]

        psid = self.code_factory.gen_series_code(media.id)
        p_series = self.property_series(category, psid, _episodes, media, action=action)
        p_series["property"].extend([
            {"LicensingWindowStart": vst},
            {"LicensingWindowEnd": vet},
            {"Kpeople": actors},
            {"Type": self._get_category_desc(category)},
            {"ActorDisplay": actors},
            {"Director": directors},
            {"ScriptWriter": writers},
            {"Isfree": 1}
        ])

        pspcid = self.code_factory.gen_media_vpic_code(media.id)
        media_verpic = self.image_resize.get_oss_resize_params(self.partner_alias, media_ext.media_verpic,
                                                               size=media_ext.verpic_size, to_ip=True,
                                                               category=self._get_category_desc(category))
        p_series_picture = self.property_picture(pspcid, media_verpic, action=action)
        mapping_series_picture = self.property_mapping("Picture", "Series", pspcid, psid, sequence=0, action=action)
        return {
            "object_list": [p_series, p_series_picture],
            "mapping_list": [mapping_series_picture]
        }

    def _album_sub_series(self, media_storage, media, episode, _episodes, action="REGIST"):
        actors, directors, writers = self.get_media_person(media, actor=4, director=4, writer=2)
        vst, vet = self.get_episode_effective_time(media.id, episode.serial_num)
        episode_title = self.get_episode_title(media, episode)
        param_dict = {"category": media.category}
        category = self.injected_change.get_injected_fields(media.id, self.lsp_pk, param_dict)["category"]

        ppid = self.code_factory.gen_program_code(media_storage.id)
        p_program = self.property_program(category, ppid, episode_title, media, action=action)
        p_program["property"].extend([
            {"ActorDisplay": actors},
            {"Director": directors},
            {"ScriptWriter": writers},
            {"Type": self._get_category_desc(category)},
            {"LicensingWindowStart": vst},
            {"LicensingWindowEnd": vet},
            {"SourceType": 1},
            {"SeriesFlag": 1},
            {"Isfree": 2},
        ])

        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)

        psid = self.code_factory.gen_series_code(media.id)
        mapping_series = self.property_mapping("Series", "Program", psid, ppid, sequence=episode.serial_num,
                                               action=action)

        pmpid = self.code_factory.gen_episode_picture_code(episode.id)
        episode_horpic = self.image_resize.get_oss_resize_params(self.partner_alias, episode.episode_horpic,
                                                                 size=episode.horpic_size, to_ip=True,
                                                                 category=self._get_category_desc(category))
        p_program_picture = self.property_picture(pmpid, episode_horpic, action=action)
        mapping_program_picture = self.property_mapping("Picture", "Program", pmpid, ppid, sequence=1, action=action)
        return {
            "object_list": [p_program, p_movie, p_program_picture],
            "mapping_list": [mapping_series, mapping_movie, mapping_program_picture],
        }

    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, episode, _episodes, action=action)
        else:  # 单剧集
            data = self._album_movie(media_storage, media, episode, media_ext, action=action)
        xml = Adi.to_xml(data, flag="Nope")
        return xml

    def exec_cmd(self, task_id, action="REGIST"):
        _task_id = self.generate_correlate_id(task_id, suffix=datetime_now())
        cmd_file_url = self.get_cmd_http_url(_task_id, view="program", action=action)
        xml = C2ApiUtil.REQUESTXML.format(self.csp_id, self.lsp_id, _task_id, cmd_file_url)
        logger.warning("{} EXEC_CMD Request: {}".format(self.lsp_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_CMD Response: {}".format(self.lsp_id, response))
        tree = etree.XML(response)
        codes = tree.xpath("//multiRef")
        desc = tree.find(".//ErrorDescription").text
        code = return_code(codes)
        if int(code) == 0:
            status = TaskStatusValue.FILE_TRANSFERING
            remark = ""
        else:
            status = TaskStatusValue.FILE_FAILED
            remark = desc

        the_task = TaskModel.objects.filter(pk=task_id)
        if the_task.first().status in (TaskStatusValue.FILE_PENDING, TaskStatusValue.INFO_PENDING):
            the_task.update(status=status, remark=remark)
        return status

    def exec_sync_header_cmd(self, sync):
        suffix = "{}{}".format(sync.action, datetime_now())
        task_id = self.generate_correlate_id(sync.id, stage="series", suffix=suffix)
        cmd_file_url = self.get_cmd_http_url(task_id, view="media")
        xml = C2ApiUtil.REQUESTXML.format(self.csp_id, self.lsp_id, task_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 = etree.XML(response)
        codes = tree.xpath("//multiRef")
        code = return_code(codes)
        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

    def injector(self, task):
        status, flag = 0, 0
        if task.status in (TaskStatusValue.FILE_PENDING, TaskStatusValue.INFO_PENDING):
            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):
            self.exec_cmd(task.id, action="UPDATE")

    def remove(self, task):
        if task.status in (TaskStatusValue.FILE_PENDING, TaskStatusValue.INFO_PENDING):
            self.exec_cmd(task.id, action="DELETE")
            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_injector(self, sync):
        if sync.status == MediaInfoSyncModel.PENDING:
            self.exec_sync_header_cmd(sync)

    def series_header_update(self, sync):
        self.series_header_injector(sync)

    def series_header_remove(self, sync):
        self.series_header_injector(sync)
