"""
@author: luojunhui
"""
import datetime
import numpy as np
import traceback

from pymysql.cursors import DictCursor

from applications.api import similarity_between_title_list
from applications.db import DatabaseConnector
from config import long_articles_config


TIMESTAMP_MS_THRESHOLD = 1732982400000
ARTICLE_BATCH = 1000
PERCENT_THRESHOLD = 95


def chunks(total_list, batch_size):
    """
    yield batch tasks
    """
    for i in range(0, len(total_list), batch_size):
        yield total_list[i:i + batch_size]


class ColdStartTitleSimilarityTask(object):
    """
    冷启动文章标题相似度任务
    """

    def __init__(self):
        self.db_client = None

    def init_database(self):
        """
        init database
        """
        self.db_client = DatabaseConnector(long_articles_config)
        self.db_client.connect()

    def get_level_up_title_list(self):
        """
        获取晋级文章标题列表
        status: 1 表示文章已经溯源完成
        deleted: 0 表示文章正常
        level = 'autoArticlePoolLevel1' 表示头条
        """
        sql = f"""
        select distinct title from article_pool_promotion_source where level = 'autoArticlePoolLevel1' and status = 1 and deleted = 0;
        """
        mysql_response = self.db_client.fetch(query=sql)
        title_list = [i[0] for i in mysql_response]
        return title_list

    def get_title_from_meta_base(self, limit):
        """
        获取meta_base表中文章标题列表
        status: 1 表示文章初始化状态
        """
        if limit:
            sql = f"""
                select article_id, title from crawler_meta_article where status = 1 and score is null limit {limit};
            """
        else:
            sql = f"""
                select article_id, title from crawler_meta_article where status = 1 and score is null;
            """
        mysql_response = self.db_client.fetch(query=sql, cursor_type=DictCursor)
        return mysql_response

    def update_meta_article_batch(self, update_data_list: list[tuple]) -> int:
        """
        批量更新crawler_meta_article
        """
        sql = """
            update crawler_meta_article
            set score = case article_id
                {}
            end
            where article_id in %s and score is null;
        """
        case_statement = []
        article_id_list = []
        params = []
        for score, article_id in update_data_list:
            case_statement.append(f"when %s then %s")
            article_id_list.append(article_id)
            params.extend([article_id, score])

        params.append(tuple(article_id_list))
        case_statements = "\n".join(case_statement)
        formatted_sql = sql.format(case_statements)
        affected_rows = self.db_client.save(formatted_sql, params)
        return affected_rows

    def run(self, limit=None):
        """
        执行任务
        """
        target_article_list = self.get_title_from_meta_base(limit=limit)
        if not target_article_list:
            print("No more articles to process.")
            return

        base_title_list = self.get_level_up_title_list()

        batch_task_list = chunks(target_article_list, ARTICLE_BATCH)

        for batch_task in batch_task_list:
            try:
                batch_target_title_list = [i['title'] for i in batch_task]
                similarity_array = similarity_between_title_list(batch_target_title_list, base_title_list)

                update_data_list = []
                for index, score_list in enumerate(similarity_array):
                    sorted_score_list = sorted(score_list)
                    percent_threshold_score = np.percentile(sorted_score_list, PERCENT_THRESHOLD)
                    update_data_list.append((percent_threshold_score, batch_task[index]['article_id']))

                affected_rows = self.update_meta_article_batch(update_data_list)

                print("{}: \t本次任务处理数量: {}".format(datetime.datetime.today().__str__(), affected_rows))
            except Exception as e:
                print("{}: \t本次任务处理失败: {}".format(datetime.datetime.today().__str__(), e))
                print(traceback.format_exc())
                continue
