# ruff: noqa: F821, I001

from __future__ import annotations

from pathlib import Path
from time import perf_counter
from typing import TYPE_CHECKING

if TYPE_CHECKING: from router import Event

class Module:
    config = {
        "banner": {"type": "boolean", "default": True, "label": {"ru": "Показывать баннер", "en": "Show banner"}},
        "image": {"type": "file", "label": {"ru": "Свой баннер", "en": "Custom banner"}},
        "nickname": {"type": "string", "max": 128, "default": "", "label": {"ru": "Ник в сообщении", "en": "Display name override"}},
        "modules": {"type": "boolean", "default": True, "label": {"ru": "Показывать число модулей", "en": "Show module count"}},
        "prefix": {"type": "boolean", "default": True, "label": {"ru": "Показывать префикс", "en": "Show prefix"}},
    }

    def __init__(self) -> None:
        self.banner, self.expires = None, 0

    @staticmethod
    def duration(seconds: int) -> str:
        days, remainder = divmod(max(0, seconds), 86400)
        hours, remainder = divmod(remainder, 3600)
        minutes, seconds = divmod(remainder, 60)
        return f"{days}d {hours:02}:{minutes:02}:{seconds:02}" if days else f"{hours:02}:{minutes:02}:{seconds:02}"

    async def image(self, ctx: Event, settings: dict) -> str | None:
        if not settings["banner"]: return None
        if settings.get("image"): return settings["image"]
        if self.banner and perf_counter() < self.expires: return self.banner

        file = await ctx.app.files.upload("cluster-ping.png", Path(__file__).with_name("banner.png").read_bytes(), ttl=3600)
        self.banner, self.expires = file["id"], perf_counter() + 1800
        return self.banner

    async def status(self, ctx: Event, settings: dict) -> str:
        info = await ctx.app.core.info()
        try: me = await ctx.app.client.get_me()
        except RuntimeError: me = {}
        nickname = settings.get("nickname") or ("@" + me["username"] if me.get("username") else info["name"])
        lines = ["Cluster is running.", "", str(nickname).replace("\n", " ").replace("\r", " ")[:128],
                 f"Core: {info['version']}", f"Core uptime: {self.duration(info['uptime'])}"]
        if settings["modules"]: lines.append(f"Modules: {info['running']} running / {info['modules']} installed")
        if settings["prefix"]: lines.append(f"Prefix: {info['prefix']}")
        return "\n".join(lines)

    @staticmethod
    def fallback(error: RuntimeError) -> bool:
        detail = error.args[0] if error.args else None
        return detail in ("access_denied", "invalid_input", "invalid_state", "quota_exceeded") or isinstance(detail, dict) and detail.get("kind") in ("forbidden", "invalid")

    async def show(self, ctx: Event, text: str, banner: str | None) -> tuple[int, bool]:
        outgoing = ctx.source == "telegram" and ctx.data.get("out", False)
        if outgoing:
            if banner:
                try:
                    await ctx.app.client.edit_file(ctx.chat_id, ctx.id, banner, caption=text)
                    return ctx.id, True
                except RuntimeError as error:
                    if not self.fallback(error): raise
            await ctx.edit(text)
            return ctx.id, False

        if banner:
            try:
                if ctx.source == "bot": result = await ctx.app.bot.send_file(ctx.chat_id, banner, kind="photo", caption=text)
                else: result = await ctx.app.client.send_file(ctx.chat_id, banner, caption=text, reply_to=ctx.id)
                return result["id"], True
            except RuntimeError as error:
                if not self.fallback(error): raise
        result = await ctx.reply(text)
        return result["id"], False

    @loader.command("ping", access="owner", source="both")
    async def ping(self, ctx: Event) -> None:
        settings = await ctx.app.config.all()
        text = await self.status(ctx, settings)
        try: banner = await self.image(ctx, settings)
        except RuntimeError: banner = None

        started = perf_counter()
        message, photo = await self.show(ctx, text, banner)
        text += f"\n\nPing: {(perf_counter() - started) * 1000:.0f} ms"
        if ctx.source == "bot":
            if photo: await ctx.app.bot.edit_caption(ctx.chat_id, message, text)
            else: await ctx.app.bot.edit_message(ctx.chat_id, message, text)
        else: await ctx.app.client.edit_message(ctx.chat_id, message, text)

    @loader.command("echo", access="owner", source="both")
    async def echo(self, ctx: Event) -> None:
        await ctx.reply(ctx.args or "Usage: echo <text>")
