from __future__ import annotations

import logging
import platform
import shutil
import sqlite3
import sys
from datetime import datetime, timezone
from pathlib import Path

from src.config import BASE_DIR, settings
from src.database import connect
from src.repositories import repo

logger = logging.getLogger(__name__)
STARTED_AT = datetime.now(timezone.utc)
BACKUP_DIR = BASE_DIR / "backups"


def _human_size(value: int) -> str:
    size = float(max(0, value))
    for unit in ("B", "KB", "MB", "GB", "TB"):
        if size < 1024 or unit == "TB":
            return f"{size:.1f} {unit}" if unit != "B" else f"{int(size)} B"
        size /= 1024
    return f"{size:.1f} TB"


def create_backup(prefix: str = "backup") -> Path:
    """Membuat backup SQLite yang konsisten saat bot sedang aktif."""
    BACKUP_DIR.mkdir(parents=True, exist_ok=True)
    destination = BACKUP_DIR / f"{prefix}-{datetime.now():%Y%m%d-%H%M%S}.sqlite3"
    source = sqlite3.connect(settings.database_path, timeout=30)
    target = sqlite3.connect(destination, timeout=30)
    try:
        source.backup(target)
    finally:
        target.close()
        source.close()
    logger.info("Backup database dibuat: %s", destination)
    return destination


def cleanup_backups(retention: int | None = None) -> int:
    """Menyimpan sejumlah backup terbaru dan menghapus sisanya."""
    if retention is None:
        try:
            retention = max(1, int(repo.setting("backup_retention", "7")))
        except (TypeError, ValueError):
            retention = 7
    BACKUP_DIR.mkdir(parents=True, exist_ok=True)
    files = sorted(BACKUP_DIR.glob("*.sqlite3"), key=lambda item: item.stat().st_mtime, reverse=True)
    removed = 0
    for old_file in files[retention:]:
        try:
            old_file.unlink()
            removed += 1
        except OSError:
            logger.warning("Gagal menghapus backup lama %s", old_file, exc_info=True)
    return removed


def auto_backup() -> Path | None:
    if repo.setting("auto_backup_enabled", "1") == "0":
        logger.info("Backup otomatis sedang dinonaktifkan")
        return None
    destination = create_backup(prefix="auto")
    cleanup_backups()
    return destination


def status_data() -> dict:
    BACKUP_DIR.mkdir(parents=True, exist_ok=True)
    backups = list(BACKUP_DIR.glob("*.sqlite3"))
    backup_size = sum(item.stat().st_size for item in backups if item.exists())
    db_size = settings.database_path.stat().st_size if settings.database_path.exists() else 0
    disk = shutil.disk_usage(BASE_DIR)
    with connect() as connection:
        delete_jobs = connection.execute("SELECT COUNT(*) AS total FROM delete_jobs").fetchone()["total"]
    uptime = datetime.now(timezone.utc) - STARTED_AT
    total_seconds = int(uptime.total_seconds())
    days, remainder = divmod(total_seconds, 86400)
    hours, remainder = divmod(remainder, 3600)
    minutes, seconds = divmod(remainder, 60)
    return {
        "uptime": f"{days} hari {hours} jam {minutes} menit {seconds} detik",
        "python": platform.python_version(),
        "platform": platform.platform(),
        "database_size": _human_size(db_size),
        "backup_count": len(backups),
        "backup_size": _human_size(backup_size),
        "delete_jobs": int(delete_jobs),
        "disk_free": _human_size(disk.free),
        "disk_total": _human_size(disk.total),
        "threads": "8",
        "executable": sys.executable,
    }


def _permission_text(member) -> str:
    status = getattr(member, "status", "unknown")
    if status == "creator":
        return "✅ Pemilik"
    if status == "administrator":
        can_post = getattr(member, "can_post_messages", True)
        can_delete = getattr(member, "can_delete_messages", True)
        missing = []
        if can_post is False:
            missing.append("kirim pesan")
        if can_delete is False:
            missing.append("hapus pesan")
        return "⚠️ Admin tanpa izin " + ", ".join(missing) if missing else "✅ Admin"
    return f"❌ Status: {status}"


def check_configuration(bot) -> list[str]:
    """Memeriksa token, channel posting/log, dan seluruh force subscribe."""
    results: list[str] = []
    me = bot.get_me()
    results.append(f"✅ Bot aktif: @{me.username} ({me.id})")

    checks = []
    if settings.channel_post_id:
        checks.append(("Channel posting", str(settings.channel_post_id)))
    else:
        results.append("⚠️ CHANNEL_POST_ID belum diisi")
    if settings.log_channel_id:
        checks.append(("Channel log", str(settings.log_channel_id)))
    else:
        results.append("ℹ️ Channel log dinonaktifkan")

    for label, chat_id in checks:
        try:
            chat = bot.get_chat(chat_id)
            member = bot.get_chat_member(chat_id, me.id)
            title = getattr(chat, "title", None) or getattr(chat, "username", None) or chat_id
            results.append(f"{_permission_text(member)} {label}: {title}")
        except Exception as exc:
            logger.warning("Pemeriksaan %s gagal", label, exc_info=True)
            results.append(f"❌ {label} tidak dapat diakses: {exc}")

    force_subs = repo.fsubs(include_inactive=False)
    if not force_subs:
        results.append("ℹ️ Force subscribe aktif: 0 channel")
    for channel in force_subs:
        try:
            chat = bot.get_chat(channel["chat_id"])
            member = bot.get_chat_member(channel["chat_id"], me.id)
            title = getattr(chat, "title", None) or channel["title"]
            results.append(f"{_permission_text(member)} FSub: {title}")
        except Exception as exc:
            logger.warning("Pemeriksaan force subscribe gagal", exc_info=True)
            results.append(f"❌ FSub {channel['title']}: {exc}")
    return results
