import re
import logging
import requests

import xml.etree.ElementTree as ET

from django.http import JsonResponse
from injector.models import TaskModel
from domain.lsp.generated.anhuizx_xsd import Adi as gz_adi
from domain.lsp.base_injector import LspInjectorC2
from domain.lsp.value_object import C2ApiUtil, CodeFactory
from domain.injector.value_object import TaskStatusValue, DefinitionValue

from utils.date_utils import datetime_now
from utils.defines import ResponseCode

logger = logging.getLogger(__file__)


class GuiZhouIpTv(LspInjectorC2):
    Media_Required_Args = ("episodes", "name", "date_published", "category", "genres", "regions",
                           "storyline", "total_seconds", "languages", "year", "douban_score")
    Episode_Required_Args = ("serial_num", "episode_horpic", "storyline")

    MediaExt_Required_Args = ("media_horpic1",)

    def __init__(self, alias="GUIZHOUIPTV"):
        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.region_sep = "|"
        self.genre_sep = "|"
        self.tag_sep = "|"

    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 "HD"
        elif definition == DefinitionValue.K4:
            return "HD"
        return "SD"

    # 分集变更规范字符串
    def trans_serial_num(self, serial_num):
        trans_num = serial_num
        if len(str(serial_num)) <= 1:
            trans_num = "0{}".format(serial_num)
        return trans_num

    # 有分集标题时
    def _have_episode_title(self, media, episode):
        fmt = "{0}{1}{2}"
        serial_num = self.trans_serial_num(episode.serial_num)
        return fmt.format(self.get_media_name_by_alias(media), "", serial_num)

    # 无分集标题时
    def _nope_episode_title(self, media, episode):
        fmt = "{0}{1}{2}"
        serial_num = self.trans_serial_num(episode.serial_num)
        return fmt.format(self.get_media_name_by_alias(media), "", serial_num)

    def transform_base_code(self, code):
        resolution = re.sub("[-_]", "", code)
        return resolution

    # series和program共有的字段
    def common_fields(self, media, category, actors, directors, definition):
        tags = self.get_genre(media)
        return [
            {"Type": self._get_category_desc(category)},
            {"Tags": tags},
            {"Keywords": tags},
            {"Language": media.languages},
            {"ActorDisplay": directors},  # ActorDisplay：导演
            {"WriterDisplay": actors},  # WriterDisplay：主演
            {"DefinitionCode": definition},
            {"ReleaseYear": media.year},
            {"OriginalCountry": self.get_regions(media)},
            {"OrgAirDate": media.date_published + " 00:00:00"},
        ]

    def property_series(self, _id, volumn_count, media, action="REGIST"):
        the_property = [
            {"Code": _id},
            {"Name": self.get_media_name_by_alias(media)},
            {"VolumnCount": volumn_count},
            {"Description": media.storyline},
            {"ReleaseYear": media.year},
            {"OriginalName": self.get_media_name_by_alias(media)},
            {"SortName": self.transform_chinese_to_letter(self.get_media_name_by_alias(media))},
            {"SearchName": self.transform_chinese_to_letter(self.get_media_name_by_alias(media))},
            {"OrgAirDate": ""},
            {"Language": media.languages},
            {"Recommendation": ""},
            {"Score": media.douban_score},
        ]
        return {
            "element_type": "Series",
            "id": _id,
            "code": _id,
            "action": action,
            "property": the_property
        }

    def property_program(self, _id, name, episode, action="REGIST"):
        return {
            "element_type": "Program",
            "id": _id,
            "code": _id,
            "action": action,
            "property": [
                {"Code": _id},
                {"Name": name},
                {"SortName": self.transform_chinese_to_letter(name)},
                {"SearchName": self.transform_chinese_to_letter(name)},
                {"OriginalName": name},
                {"VolumnCount": episode.serial_num},
                {"Status": 1},
            ]
        }

    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},
                {"FileSize": media_storage.size},
                {"Md5": media_storage.md5},
                {"BitrateId": int(media_storage.bit_rate)},
            ]
        }

    def _album(self, media_storage, media, episode, media_ext, action):
        actors, directors, writers = self.get_media_person(media, actor=4, director=4, writer=2)
        vst, vet = self.get_media_effective_time(media.id)
        e_vst, e_vet = self.get_episode_effective_time(media.id, episode.serial_num)

        if media_ext.media_verpic1:

            media_verpic = self.image_resize.get_oss_resize_params(self.partner_alias, media_ext.media_verpic1,
                                                               size=media_ext.verpic_size1, to_ip=True)
            media_horpic = self.image_resize.get_oss_resize_params(self.partner_alias, media_ext.media_horpic1,
                                                               size=media_ext.horpic_size1, to_ip=True)
        else:
            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)

        episode_horpic = self.image_resize.get_oss_resize_params(self.partner_alias, episode.episode_horpic,
                                                                 size=episode.horpic_size, to_ip=True)
        episode_title = self.get_episode_title(media, episode)
        definition = self._get_bit_rate_type(media_storage.definition)
        param_dict = {"category": media.category}
        change_fields = self.injected_change.get_injected_fields(media.id, self.lsp_pk, param_dict)
        common_fields = self.common_fields(media, change_fields["category"], actors, directors, definition)

        _psid = self.code_factory.gen_series_code(media.id)
        psid = self.transform_base_code(_psid)
        p_series = self.property_series(psid, media.episodes, media, action=action)
        p_series["property"].extend(common_fields)
        p_series["property"].extend([
            {"PictureURL1": self.to_ip_url(media_verpic)},
            {"HorizontalPoster": self.to_ip_url(media_horpic)},
            {"LicensingWindowStart": vst},
            {"LicensingWindowEnd": vet},
        ])

        _ppid = self.code_factory.gen_program_code(media_storage.id)
        ppid = self.transform_base_code(_ppid)
        p_program = self.property_program(ppid, episode_title, episode, action)
        p_program["property"].extend(common_fields)
        p_program["property"].extend([
            {"Description": episode.storyline if episode.storyline else media.storyline},
            {"PictureURL1": self.to_ip_url(episode_horpic)},
            {"ProgramLength": int((media_storage.seconds + 60) / 60)},
            {"LicensingWindowStart": e_vst},
            {"LicensingWindowEnd": e_vet}

        ])
        mapping_program = self.property_mapping("Series", "Program", psid, ppid, sequence=episode.serial_num,
                                                action=action)

        _pmid = self.code_factory.gen_movie_code(media_storage.id)
        pmid = self.transform_base_code(_pmid)
        p_movie = self.property_movie(pmid, media_storage, action=action)
        p_movie["property"].extend([{"DefinitionCode": definition}])
        mapping_movie = self.property_mapping("Program", "Movie", ppid, pmid, action=action)
        return {
            "domain": "2",
            "object_list": [p_series, p_program, p_movie],
            "mapping_list": [mapping_program, mapping_movie]
        }

    def album(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
        data = self._album(media_storage, media, episode, media_ext, action)
        xml = gz_adi.to_xml(data, flag="Nope")
        return xml

    def exec_cmd(self, task_id):
        _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
        desc = tree.find(".//ErrorDescription").text
        if int(code) == 0:
            status = TaskStatusValue.FILE_TRANSFERING
            remark = ""
        else:
            status = TaskStatusValue.FILE_FAILED
            remark = desc

        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)
            self.save_album_xml_file(self.csp_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.save_album_xml_file(self.csp_id, _task_id, action="UPDATE")
            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, 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))
