import logging
import requests
import xml.etree.ElementTree as ET
from injector.models import TaskModel
from injector.models import CdnMediaInformation
from injector.models import CdnEpisodeInformation

from domain import domain_except
from domain.lsp.base_injector import LspInjectorC2
from domain.lsp.value_object import C2ApiUtil, CodeFactory
from domain.injector.media_storage_domain import MediaStorage
from domain.injector.value_object import TaskStatusValue, DefinitionValue

from domain.lsp.generated.common_xsd import Adi
from utils.date_utils import datetime_now

logger = logging.getLogger(__file__)


class AnHuiDianXing(LspInjectorC2):
    CDN_Media_Required_Args = ("verpic", "horpic", "category", "definition", "is_charge", "status")
    CND_Episode_Required_Args = (
        "play_url", "episode_horpic", "episode_id", "storage_type", "storage_definition", "status", "is_charge")
    MediaExt_Required_Args = ("focus",)

    def __init__(self, alias="ANHUIDIANXING"):
        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.cast_sep = ";"
        self.genre_sep = "|"

    def check_module_args(self, model, keys):
        for key in keys:
            value = getattr(model, key)
            if not value and str(value) != "0":
                raise domain_except.ParamRequiredException("缺少必填参数:{}".format(key))

    def check_args(self, storage_id):
        """校验参数是不是全"""
        video = MediaStorage.model.objects.select_related('media', 'episode').get(id=storage_id)
        cdn_media = CdnMediaInformation.objects.get(media=video.media, partner_id=self.lsp_pk)
        cdn_work_order = CdnEpisodeInformation.objects.get(
            episode=video.episode, cdn_media_id=cdn_media.id, storage_id=storage_id
        )
        self.check_module_args(video.media, self.Media_Required_Args)
        self.check_module_args(cdn_media, self.CDN_Media_Required_Args)
        self.check_module_args(cdn_work_order, self.CND_Episode_Required_Args)
        self.check_module_args(video.media.mediaextfieldmodel, self.MediaExt_Required_Args)
        return

    def _get_bit_rate_type(self, definition):
        if definition == DefinitionValue.P480:
            return 1
        elif definition == DefinitionValue.P720:
            return 3
        elif definition == DefinitionValue.P1080:
            return 4
        elif definition == DefinitionValue.K4:
            return 6
        return 1

    def get_genre(self, media_obj):
        genres = media_obj.genres
        if genres and len(genres):
            names = [genre["name"] for genre in genres]
            type2, tags = names[0], names[1:]
            return type2, self.genre_sep.join(names)
        return "", ""

    # 有分集标题时
    def _have_episode_title(self, media, episode):
        fmt = "{0}{1}第{2}集"
        return fmt.format(self.get_media_name_by_alias(media), " ", episode.serial_num)

    # 安徽电信转换code
    def transform_base_code(self, code):
        resolution = code.replace("-", "")
        return resolution

    # 返回上下线状态
    def get_status(self, _status, action="REGIST"):
        return 1 if action == "DELETE" else 1 - _status

    def property_series(self, _id, cdn_media, media, media_ext, action="REGIST"):
        type2, tags = self.get_genre(media)
        the_property = [
            {"Name": self.get_media_name_by_alias(media)},
            {"Bcharging": cdn_media.is_charge},
            # 安徽电信目前只有产品包业务
            {"Chargingmode": 1},
            {"VolumnCount": media.episodes},
            # 安徽电信0为上线，1为下线
            {"Status": self.get_status(cdn_media.status, action)},
            {"Description": media.storyline},
            {"ShortDesc": media_ext.focus},
            {"SeriesType": 1 if int(media.episodes) > 1 else 2},
            {"Tags": tags},
            {"ReleaseYear": media.year},
            {"ProgramType": self._get_category_desc(cdn_media.category)},
            {"ProgramType2": type2},
            {"TvPosterUrl1": cdn_media.verpic},
            {"TvPosterUrl2": cdn_media.horpic},
            # 安徽tv机、phone手机端
            {"terminalId": "tv"},
            {"metaType": 0 if int(media.episodes) > 1 else 1}
        ]
        return {
            "element_type": "Series",
            "id": _id,
            "code": _id,
            "action": action,
            "property": the_property
        }

    def property_program(self, _id, episode_title, episodes, cdn_work, action="REGIST"):
        the_property = [
            {"Name": episode_title},
            {"VolumnCount": episodes},
            {"PosterUrl1": cdn_work.episode_horpic},
            {"PosterUrl2": cdn_work.episode_verpic},
            # 安徽电信0为上线，1为下线
            {"Status": self.get_status(cdn_work.status, action)},
            {"Bcharging": cdn_work.is_charge},
        ]
        return {
            "element_type": "Program",
            "id": _id,
            "code": _id,
            "action": action,
            "property": the_property
        }

    def property_movie(self, _id, cdn_work, action="REGIST"):
        return {
            "element_type": "Movie",
            "id": _id,
            "code": _id,
            "action": action,
            "property": [
                {"Type": cdn_work.storage_type},
                {"PlayURL": cdn_work.play_url},
                # 安徽电信0为上线，1为下线
                {"Status": self.get_status(cdn_work.status, action)},
                {"Definition": self._get_bit_rate_type(cdn_work.storage_definition)},
            ]
        }

    def _program(self, storage, media, episode, media_ext, action):
        cdn_media = CdnMediaInformation.objects.filter(media_id=media.id, partner_id=self.lsp_pk).first()
        cdn_work_order = CdnEpisodeInformation.objects.filter(
            episode_id=episode.id, cdn_media_id=cdn_media.id, storage_id=storage.id
        ).first()
        actors, directors, _ = self.get_media_person(media, actor=4, director=4, writer=2)
        episodes = int(episode.serial_num)
        episode_title = self.get_episode_title(media, episode)

        _psid = self.code_factory.gen_series_code(media.id)
        psid = self.transform_base_code(_psid)
        p_series = self.property_series(psid, cdn_media, media, media_ext, action=action)
        p_series["property"].extend([
            {"ActorDisplay": directors},
            {"WriterDisplay": actors},
        ])
        _ppid = self.code_factory.gen_program_code(storage.id)
        ppid = self.transform_base_code(_ppid)
        p_program = self.property_program(ppid, episode_title, episodes, cdn_work_order, action=action)
        mapping_program = self.property_mapping("Series", "Program", psid, ppid, sequence=episode.serial_num, action=action)
        _pmid = self.code_factory.gen_movie_code(storage.id)
        pmid = self.transform_base_code(_pmid)
        p_movie = self.property_movie(pmid, cdn_work_order, action=action)
        mapping_movie = self.property_mapping("Program", "Movie", ppid, pmid, action=action)
        return [p_series, p_program, p_movie], [mapping_program, mapping_movie]

    def program(self, task_id, action="REGIST"):
        task_id = task_id.split("_", 1)[0]
        task = TaskModel.objects.filter(pk=task_id).select_related("storage").first()
        storage = task.storage
        media = storage.media
        episode = storage.episode
        media_ext = media.mediaextfieldmodel
        object_list, mapping_list = self._program(storage, media, episode, media_ext, action)
        data = {
            "object_list": object_list,
            "mapping_list": mapping_list,
        }
        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())
        http_url = self.get_cmd_http_url(_task_id, view="program", action=action)
        xml = C2ApiUtil.AHDX_REQUESTXML.format(self.csp_id, self.lsp_id, _task_id, http_url)
        logger.warning("EXEC_CMD Request: {}".format(xml))
        headers = {"content-type": "text/xml;charset=utf8", "SOAPAction": ""}
        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
        desc = tree.find(".//errorDescription").text
        status = TaskStatusValue.FILE_FAILED
        remark = desc
        if int(code) == 0:
            status = TaskStatusValue.FILE_TRANSFERING
            remark = ""
        TaskModel.objects.filter(pk=task_id).update(status=status, remark=remark)
        return status

    def injector(self, task):
        status, flag = 0, 0
        if task.status in (TaskStatusValue.FILE_PENDING, TaskStatusValue.INFO_PENDING):
            _task_id = self.generate_correlate_id(task.id)
            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.exec_cmd(task.id, action="UPDATE")

    def remove(self, task):
        if task.status in (TaskStatusValue.FILE_PENDING, TaskStatusValue.INFO_PENDING):
            _task_id = self.generate_correlate_id(task.id)
            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))
