from django.core.paginator import Paginator

from domain.lsp.value_object import LspExtendConfig
from injector.models import TaskModel, LSP
from injector.models import MediaStorageModel
from injector.models import MediaInfoSyncModel
from injector.models import CdnMediaInformation
from injector.models import PartnerMediaStorageModel
from injector.models import InjectedFieldChangeModel
from injector.models import MediaModel
from imdb.models import EpisodeEffectiveTimeModel

from domain.imdb.value_object import CategoryValue
from domain.injector.value_object import TaskStatusValue


class PlatFormMedia:
    episode_model = TaskModel
    sync_model = MediaInfoSyncModel
    storage_mode = MediaStorageModel
    show_model = PartnerMediaStorageModel
    change_model = InjectedFieldChangeModel
    cdn_model = CdnMediaInformation

    def search_for_export(self, lsp_id, create_time):
        query = dict()
        if lsp_id:
            query["partner_id"] = int(lsp_id)
        if create_time:
            query["create_time__gt"] = create_time
            query_set = self.episode_model.objects.filter(**query).values_list("media_id").distinct()
            md_list = [x[0] for x in query_set]
            query["media_id__in"] = md_list
            query.pop("create_time__gt")
        print(query)
        queryset = self.episode_model.objects.filter(**query).select_related('episode').values("id", "media_id",
                                                                                               "status", "action",
                                                                                               "episode__serial_num",
                                                                                               "create_time").order_by(
            "-create_time")

        m_id_list = set()
        media_dict = {}
        task_count = {}
        task_time = {}

        for item in queryset:
            m_id_list.add(item["media_id"])
            if item["media_id"] in task_count:
                task_count[item["media_id"]]["all"] += 1
                task_time[item["media_id"]]["start"] = item["create_time"]
            else:
                task_count[item["media_id"]] = {"all": 1, "success_list": [], "fail_list": [], "pend_list": [],
                                                "repeat_dict": {}, "delete_list": []}
                task_time[item["media_id"]] = {"start": item["create_time"], "end": item["create_time"]}

            if item["action"] == 3:
                task_count[item["media_id"]]["delete_list"].append(item["episode__serial_num"])
            else:
                if item["status"] == TaskStatusValue.INFO_COMPLETED:
                    if item["episode__serial_num"] in task_count[item["media_id"]]["repeat_dict"]:
                        task_count[item["media_id"]]["repeat_dict"][item["episode__serial_num"]] += 1
                    else:
                        task_count[item["media_id"]]["success_list"].append(item["episode__serial_num"])
                        task_count[item["media_id"]]["repeat_dict"][item["episode__serial_num"]] = 1
                elif item["status"] in TaskStatusValue.failed():
                    task_count[item["media_id"]]["fail_list"].append(item["episode__serial_num"])
                else:
                    task_count[item["media_id"]]["pend_list"].append(item["episode__serial_num"])

        queryset = MediaModel.objects.filter(id__in=m_id_list).values("id", "name", "episodes")
        new_m_id_list = set()
        for item in queryset:
            new_m_id_list.add(item["id"])
            media_dict[item["id"]] = {"name": item["name"], "episodes": item["episodes"], "category": "未知"}
        print("diss:{}".format(m_id_list - new_m_id_list))
        m_id_list = new_m_id_list
        queryset = InjectedFieldChangeModel.objects.filter(partner_id=lsp_id, media_id__in=m_id_list).values("media_id",
                                                                                                        "category")
        for item in queryset:
            media_dict[item["media_id"]]["category"] = item["category"]

        partner_name = LSP.objects.filter(id=lsp_id).values("name").first().get("name", "未知")

        """
        item['partner_name'], item['media_id'], item['media_name'], item['change_category'],
            item['media_episodes'], item['valid_num'], item['invalid_num'], item['injector_num'],
            "’{}".format(item['start_time']), "’{}".format(item['end_time'])
        """

        result = []
        for m_id in m_id_list:
            row = {"media_id": m_id, "media_name": media_dict[m_id]["name"],
                   "change_category": media_dict[m_id]["category"], "media_episodes": media_dict[m_id]["episodes"],
                   "partner_name": partner_name,
                   "un_num": media_dict[m_id]["episodes"] - len(task_count[m_id]["success_list"]),
                   "status": "完成" if media_dict[m_id]["episodes"] - len(
                       task_count[m_id]["success_list"]) == 0 else "未完成",
                   "valid_num": len(task_count[m_id]["success_list"]),
                   "un_list": self.trans_sub_seq(
                       list(set(range(1, media_dict[m_id]["episodes"] + 1)) - set(task_count[m_id]["success_list"]))),
                   "fail_list": self.trans_sub_seq(task_count[m_id]["fail_list"]),
                   "pend_list": self.trans_sub_seq(task_count[m_id]["pend_list"]),
                   "re_list": self.trans_sub_seq(
                       [key for key, val in task_count[m_id]["repeat_dict"].items() if val > 1]),
                   "delete_list": self.trans_sub_seq(task_count[m_id]["delete_list"]),
                   "injector_num": task_count[m_id]["all"],
                   "start_time": task_time[m_id]["start"].strftime("%Y-%m-%d %H:%M:%S"),
                   "end_time": task_time[m_id]["end"].strftime("%Y-%m-%d %H:%M:%S")
                   }
            print(row)
            result.append(row)
        return result, 0, 0

    def trans_sub_seq(self, s):
        if len(s) <= 1:
            return s
        ns = []
        s = sorted(s, reverse=False)
        tem_s = []
        for i in range(len(s)):
            if i == 0:
                tem_s.append(s[i])
                continue
            if s[i] - s[i - 1] == 1:
                tem_s.append(s[i])
                print("i:{}".format(i))
                if i == len(s) - 1:
                    ts = "{}-{}".format(tem_s[0], tem_s[-1])
                    ns.append(ts)
            else:
                print("else:{}".format(i))
                print(tem_s)
                if len(tem_s) >= 2:
                    ts = "{}-{}".format(tem_s[0], tem_s[-1])
                else:
                    ts = tem_s[0]
                ns.append(ts)
                tem_s = [s[i]]
                if i == len(s) - 1:
                    ns.append(s[i])
        return ns

    def search(self, media_name, lsp_id, create_time, page=1, page_size=20, lsp_ids=None):
        query = dict()
        if media_name:
            query["media__name__contains"] = media_name
        if lsp_id:
            query["partner_id"] = int(lsp_id)
        if create_time:
            query["create_time__gt"] = create_time

        if lsp_ids:
            query["partner_id__in"] = lsp_ids

        query_set = self.episode_model.objects.filter(**query).select_related("media", "partner"). \
            values("media_id", "media__name", "media__category", "partner_id", "partner__name", "media__episodes",
                   "partner__is_cdn", "partner__series_first").distinct()

        data = self._get_list(query_set, page, page_size)
        return data

    # 获取注入情况媒体类型
    def get_category(self, media_id, partner_id, media_category, is_cdn=False):
        if is_cdn:
            cdn_media = self.cdn_model.objects.filter(media_id=int(media_id), partner_id=int(partner_id)).first()
            category = cdn_media.category if cdn_media else media_category
        else:
            change_media = self.change_model.objects.filter(media_id=int(media_id), partner_id=int(partner_id)).first()
            category = change_media.category if change_media else media_category
        return category

    def get_injector_time(self, vst, vet, inv_st, inv_et, media_id, partner_id, series_flag=False):
        """
        :param vst: 有效集数注入的开始时间
        :param vet: 有效集数注入的结束时间
        :param inv_st: 无效集数注入的开始时间
        :param inv_et: 无效集数注入的结束时间
        :param media_id:
        :param partner_id:
        :param series_flag: 注入是否需要剧头
        :return:
        """
        if vst:
            start_time, end_time = vst, vet
        elif inv_st:
            start_time, end_time = inv_st, inv_et
        else:
            start_time, end_time = "", ""
        if series_flag:
            sync_media = self.sync_model.objects.filter(media_id=int(media_id), partner_id=int(partner_id)).first()
            start_time = sync_media.create_time if sync_media else start_time
            if not end_time:
                end_time = sync_media.update_time if sync_media else end_time
        return start_time, end_time

    # join表PartnerMediaStorageModel返回数据
    def join_is_show(self, media_id, partner_id):
        objs = self.episode_model.objects.raw(f"""
            SELECT 
                task.*, pms.is_show as is_show
            from injector_task as task JOIN injector_partner_media_storage as pms 
                on task.storage_id=pms.storage_id and task.partner_id=pms.partner_id 
            WHERE task.media_id={int(media_id)} and task.partner_id={int(partner_id)} 
            and task.status={TaskStatusValue.INFO_COMPLETED};
        """)
        result = dict()
        for obj in objs:
            is_show = obj.__dict__.get("is_show")
            if not result.get(is_show, ""):
                result[is_show] = {"st": list(), "et": list()}
            result[is_show]["st"].append(obj.create_time)
            result[is_show]["et"].append(obj.create_time)
        return result

    # 获取注入情况有效集数，无效集数，总集数，和注入成功的时间段
    def get_injector_item(self, media_id, partner_id):
        join_data = self.join_is_show(media_id, partner_id)
        valid_num = 0
        invalid_num = 0
        vst, vet, invst, invet = "", "", "", ""

        for is_show, time_data in join_data.items():
            sts, ets = time_data.get("st", list()), time_data.get("et", list())
            if is_show:
                vst = min(sts)
                vet = max(ets)
                valid_num = len(sts)
            else:
                invst = min(sts)
                invet = max(ets)
                invalid_num = len(sts)
        return valid_num, invalid_num, vst, vet, invst, invet

    def to_dict(self, item):
        """{
            "media_id": 1231, "media__name": "网络年代", "media__category": "tvseries", "partner_id": 1,
            "partner__name": "银河TV", "media__episodes": 21, "partner__is_cdn": False,
            "partner__series_first": False}
        """
        media_id = item["media_id"]
        media_name = item["media__name"]
        partner_id = item["partner_id"]
        partner_is_cdn = item["partner__is_cdn"]
        partner_name = item["partner__name"]
        media_episodes = item["media__episodes"]
        media_category = item["media__category"]
        series_flag = item["partner__series_first"]
        change_category = self.get_category(media_id, partner_id, media_category, partner_is_cdn)
        valid_num, invalid_num, vst, vet, inv_st, inv_et = self.get_injector_item(media_id, partner_id)
        _start_time, _end_time = self.get_injector_time(vst, vet, inv_st, inv_et, media_id, partner_id, series_flag)
        start_time = _start_time.strftime("%Y-%m-%d %H:%M:%S") if _start_time else ""
        end_time = _end_time.strftime("%Y-%m-%d %H:%M:%S") if _end_time else ""
        return {
            "media_id": media_id, "media_name": media_name, "partner_id": partner_id, "partner_name": partner_name,
            "media_episodes": media_episodes, "start_time": start_time, "end_time": end_time,
            "media_category": CategoryValue.desc(media_category),
            "change_category": CategoryValue.desc(change_category),
            "valid_num": valid_num, "invalid_num": invalid_num, "injector_num": valid_num + invalid_num
        }

    def _get_list(self, query, page, page_size):
        if page and page_size:
            pager = Paginator(query, page_size)
            obj_list = pager.get_page(page)
            total_page = pager.num_pages
            total_item = pager.count
        else:
            obj_list = query
            total_page, total_item = 0, 0
        result = [self.to_dict(obj) for obj in obj_list]
        return result, total_page, total_item

    def get_series_detail(self, sync_id):
        sync = self.sync_model.objects.filter(id=sync_id).first()
        alias = sync.partner.alias
        category1 = sync.media.category
        return self.get_category_charge_times(sync.media_id, sync.partner_id, alias, category1)

    def get_task_series_detail(self, task_id):
        task = TaskModel.objects.filter(id=task_id).first()
        alias = task.partner.alias
        is_set_effective_time = task.partner.is_set_effective_time
        series_first = task.partner.series_first
        category1 = task.media.category
        return self.get_category_charge_times(task.media_id, task.partner_id, alias, category1, is_set_effective_time,
                                              series_first)

    def get_category_charge_times(self, media_id, partner_id, alias, category1, is_time=True, series_first=True):
        change_obj = self.change_model.objects.filter(media_id=media_id, partner_id=partner_id).first()
        time_obj = EpisodeEffectiveTimeModel.objects.filter(media_id=media_id, partner_id=partner_id).first()
        channel = LspExtendConfig.get_constraint_category(alias)
        category = change_obj.category
        is_charge = change_obj.is_charge
        times = None
        if time_obj:
            effective_times = time_obj.effective_times
            times = effective_times[list(effective_times)[0]]

        return {"is_charge": is_charge, "category": category, "times": times, "media_category": category1,
                "channel": channel, "is_time": is_time, "series_first": series_first}

    def update_series_detail(self, sync_id, category, is_charge, times):
        sync = self.sync_model.objects.filter(id=sync_id).first()
        media_id = sync.media_id
        partner_id = sync.partner_id
        self.update_category_charge(media_id, partner_id, category, is_charge, times)

    def update_task_series_detail(self, task_id, category, is_charge, times):
        task = TaskModel.objects.filter(id=task_id).first()
        self.update_category_charge(task.media_id, task.partner_id, category, is_charge, times)

    def update_category_charge(self, media_id, partner_id, category, is_charge, times):
        self.change_model.objects.filter(media_id=media_id, partner_id=partner_id).update(category=category,
                                                                                          is_charge=is_charge)

        time_obj = EpisodeEffectiveTimeModel.objects.filter(media_id=media_id, partner_id=partner_id).first()
        if time_obj:
            effective_times = time_obj.effective_times
            for key in effective_times:
                effective_times[key] = times
            time_obj.effective_times = effective_times
            time_obj.save()
