"""
UI утилиты TelePush — замена bot_ui.ui из бота.
Без Telegram зависимостей.
"""
import time
import state
from models import OwnerCtx


def get_ctx(uid: int) -> OwnerCtx:
    """Возвращает (или создаёт) per-user контекст.
    ВАЖНО: при создании нового ctx ОБЯЗАТЕЛЬНО подгружаем user_settings с диска.
    Иначе scheduler.autoload_all_users() создаст ctx с дефолтами при старте программы,
    потом Flask увидит ctx-уже-есть и не подгрузит настройки → клиент видит
    дефолтные тайминги → нажимает «Сохранить» → записываются дефолты → старые
    настройки клиента затёрты. Этот баг мы ловили как «тайминги сбрасываются
    после каждого перезапуска»."""
    with state.owners_lock:
        ctx = state.owners.get(uid)
        if ctx is None:
            ctx = OwnerCtx()
            ctx.temp["_settings_loaded_ok"] = False
            try:
                # Импорт лениво — избегаем циркулярной зависимости bot_ui → web.app
                from web.app import _load_user_settings as _lus
                saved = _lus()
                if saved:
                    ctx.user_settings.update(saved)
                    ctx.temp["_settings_loaded_ok"] = True
                    import logging as _lg
                    _lg.getLogger("telepush").info(
                        "[ctx] uid=%s: загружено %d ключей настроек (через bot_ui.get_ctx)",
                        uid, len(saved),
                    )
                else:
                    ctx.temp["_settings_loaded_ok"] = True
            except Exception as _e:
                import logging as _lg
                _lg.getLogger("telepush").debug(
                    "[ctx] uid=%s: load settings failed (%s) — будут дефолты", uid, _e,
                )
            state.owners[uid] = ctx
        return ctx


def progress_bar(done: int, total: int, width: int = 20) -> str:
    total = max(total, 1)
    pct = min(100, int(done * 100 / total))
    filled = int(round(width * done / total))
    return f"[{'█' * filled}{'░' * (width - filled)}] {pct}%"


def progress_bar_detailed(done: int, total: int) -> str:
    return progress_bar(done, total)


def _eta_text(processed, total, started_at):
    if processed <= 0 or not started_at:
        return "~"
    elapsed = time.time() - float(started_at)
    if elapsed < 1:
        return "~"
    speed = processed / elapsed
    remaining = (total - processed) / speed if speed > 0 else 0
    if remaining < 60:
        return f"~{int(remaining)}с"
    elif remaining < 3600:
        return f"~{int(remaining // 60)}мин {int(remaining % 60)}с"
    else:
        h = int(remaining // 3600)
        m = int((remaining % 3600) // 60)
        return f"~{h}ч {m}мин"


def _status_label(status):
    labels = {
        "idle": "⏳ Ожидание",
        "running": "▶️ Работает",
        "paused": "⏸ Пауза",
        "finished": "🏁 Завершено",
        "stopped": "⏹ Остановлено",
    }
    return labels.get(status, status)


def _md_code(text, max_len=100):
    if not text:
        return "—"
    t = str(text)[:max_len]
    return f"`{t}`"


def _job_log_add(job, text):
    try:
        from models import log_append
        log_append(job.log_lines, text)
    except Exception:
        pass


async def _sleep_with_job_ui(job, seconds, reason="", update_every=10):
    """Спит с обновлением current_step."""
    import asyncio
    remaining = seconds
    while remaining > 0 and not job.stop_flag:
        if reason:
            job.current_step = f"{reason} ({int(remaining)}с)"
        step = min(update_every, remaining)
        await asyncio.sleep(step)
        remaining -= step


def _job_log_text(job, limit=20):
    lines = getattr(job, "log_lines", []) or []
    return "\n".join(lines[-limit:])
