import asyncio
import inspect
from datetime import datetime

from public.times import Times
from init import Init


class Report(Init):
    def __init__(self, coin):
        super().__init__(coin, "report")

    async def query_mysql_last_height(self):
        sql = f"SELECT MAX(height) AS max_height FROM {self.coin}_blkreportprofitv2;"
        data = await self.distribution.exec(sql)
        if not data or data[0]["max_height"] is None:
            raise ValueError(f"{self.coin}当前无报块记录")
        return data[0]["max_height"]

    async def query_redis_last_height(self):
        data = await self.redis.get(f"{self.coin}:last_check")
        if not data:
            result = await self.query_mysql_last_height()
            await self.redis.set(f"{self.coin}:last_check", result)
            print(f"redis中无{self.coin} last_check数据，采用最后一个报块高度！")
            return result
        return int(data)

    async def query_chain_last_height(self):
        return int(await self.node.getblockcount())

    async def insert_blkreportprofit(self, data):
        sql = f"""
        INSERT INTO {self.coin}_blkreportprofitv2
        (date, height, hash, reward, fees, state)
        VALUES
        """
        values = []
        for item in data:
            sql += "(?,?,?,?,?,?),"
            values.extend([
                item["date"],
                item["height"],
                item["hash"],
                item["reward"],
                item["fees"],
                0
            ])
        sql = sql.rstrip(",")
        await self.distribution.exec_transaction(sql, values)

    async def main(self):
        redis_height, chain_height = await asyncio.gather(
            self.query_redis_last_height(),
            self.query_chain_last_height()
        )

        if chain_height < redis_height:
            print(f"{self.coin}节点同步出错，节点高度{chain_height}，last_check{redis_height}")
            return

        if chain_height == redis_height:
            print(f"{self.coin}当前节点和last_check高度一致，无需校验")
            return

        suc_data = []

        for height in range(redis_height + 1, chain_height + 1):
            check_result = await self.node.verify_block(height, self.REPORT_ADDRESS)
            if not check_result:
                continue

            block_ret = self.node.block(check_result)
            if inspect.isawaitable(block_ret):
                block = await block_ret
            else:
                block = block_ret

            suc_data.append({
                "date": Times.utcTime(block["time"] * 1000),
                "height": block["height"],
                "hash": block["hash"],
                "reward": str(block["block_reward"]),
                "fees": block["block_fees"]
            })

        if not suc_data:
            print(f"{redis_height} - {chain_height} 无报块")
            await self.redis.set(f"{self.coin}:last_check", chain_height)
            return

        await self.insert_blkreportprofit(suc_data)
        await self.redis.set(f"{self.coin}:last_check", chain_height)


class ReportEnx(Report):
    async def query_blkstats(self, height):
        yesterday = Times.utcTime(
            int(datetime.now().timestamp() * 1000) - 86400000
        ).split(" ")[0].replace("-", "")

        table1 = "enx_pool_blkstats"
        table2 = f"enx_pool_blkstats_{yesterday}"

        exist_sql = "SHOW TABLES LIKE %s;"
        exist = await self.pooldb.exec(exist_sql, [table2])

        if not exist:
            sql = f"SELECT date, height, hash FROM {table1} WHERE height > %s;"
            return await self.pooldb.exec(sql, [height])

        sql = f"""
        SELECT date, height, hash FROM {table1} WHERE height > %s
        UNION ALL
        SELECT date, height, hash FROM {table2} WHERE height > %s;
        """
        return await self.pooldb.exec(sql, [height, height])

    async def query_blkreportprofit(self):
        sql = f"SELECT MAX(height) AS max_height FROM {self.coin}_blkreportprofitv2;"
        data = await self.distribution.exec(sql)
        if not data or data[0]["max_height"] is None:
            return 0
        return data[0]["max_height"]

    async def insertinto_blkreportprofit(self, data):
        sql = f"""
        INSERT INTO {self.coin}_blkreportprofitv2
        (date, height, hash, reward, fees, state)
        VALUES
        """
        values = []
        for item in data:
            sql += "(?,?,?,?,?,?),"
            values.extend([
                item["date"],
                item["height"],
                item["hash"],
                item["reward"],
                0,
                1
            ])
        sql = sql.rstrip(",")
        await self.distribution.exec_transaction(sql, values)

    async def main(self):
        last_height = await self.query_blkreportprofit()
        data = await self.query_blkstats(last_height)

        if not data:
            print(f"{self.coin} 无报块")
            return

        block_data = [
            {
                "date": item["date"],
                "height": item["height"],
                "hash": item["hash"],
                "reward": 333
            }
            for item in data
        ]

        await self.insertinto_blkreportprofit(block_data)


__all__ = ["Report", "ReportEnx"]