"""
Портал приложений — Flask сервер на порту 5560.
При старте автогенерирует аватарки для приложений из config/apps.json.
"""

import json
import hashlib
from pathlib import Path

from flask import Flask, render_template, jsonify, send_from_directory
from PIL import Image, ImageDraw, ImageFont

BASE_DIR = Path(__file__).parent
CONFIG_FILE = BASE_DIR / "config" / "apps.json"
AVATARS_DIR = BASE_DIR / "static" / "avatars"

app = Flask(__name__)


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

def load_apps():
    """Загружает и возвращает активные приложения, отсортированные по order."""
    with open(CONFIG_FILE, "r", encoding="utf-8") as f:
        apps = json.load(f)
    return sorted(
        [a for a in apps if a.get("enabled", True)],
        key=lambda x: x.get("order", 99),
    )


def _hash_color(text: str, offset: int = 0) -> tuple[int, int, int]:
    """Детерминированно генерирует RGB-цвет из строки (с optional offset для второго цвета)."""
    digest = hashlib.md5((text + str(offset)).encode()).hexdigest()
    r = int(digest[0:2], 16)
    g = int(digest[2:4], 16)
    b = int(digest[4:6], 16)
    # Сдвигаем яркость так, чтобы фон был насыщенным, не слишком тёмным и не белым
    r = max(60, min(r, 200))
    g = max(60, min(g, 200))
    b = max(60, min(b, 200))
    return (r, g, b)


def _make_gradient(size: int, color1: tuple, color2: tuple) -> Image.Image:
    """Создаёт квадратное изображение с линейным градиентом (135°)."""
    img = Image.new("RGB", (size, size))
    draw = ImageDraw.Draw(img)
    for y in range(size):
        for x in range(size):
            t = (x + y) / (size * 2)  # 0..1 вдоль диагонали 135°
            r = int(color1[0] * (1 - t) + color2[0] * t)
            g = int(color1[1] * (1 - t) + color2[1] * t)
            b = int(color1[2] * (1 - t) + color2[2] * t)
            draw.point((x, y), fill=(r, g, b))
    return img


def _hash_gradient(name: str):
    """Возвращает два цвета для градиента по хэшу имени."""
    h = int(hashlib.md5(name.encode()).hexdigest()[:8], 16)
    palettes = [
        ("#667eea", "#764ba2"),
        ("#f093fb", "#f5576c"),
        ("#4facfe", "#00f2fe"),
        ("#43e97b", "#38f9d7"),
        ("#fa709a", "#fee140"),
        ("#a18cd1", "#fbc2eb"),
        ("#ffecd2", "#fcb69f"),
        ("#ff9a9e", "#fad0c4"),
        ("#a1c4fd", "#c2e9fb"),
        ("#d4fc79", "#96e6a1"),
    ]
    return palettes[h % len(palettes)]


def generate_avatar(app_cfg: dict) -> Path:
    """
    Генерирует аватарку для одного приложения и сохраняет в static/avatars/{id}.png.
    Возвращает путь к файлу.
    """
    app_id = app_cfg["id"]
    name = app_cfg.get("name", app_id)
    icon = app_cfg.get("icon", name[0].upper())

    out_path = AVATARS_DIR / f"{app_id}.png"
    if out_path.exists():
        return out_path

    size = 200
    color1 = _hash_color(name, offset=0)
    color2 = _hash_color(name, offset=1)

    img = _make_gradient(size, color1, color2)
    _draw_letter(img, name, size)

    out_path.parent.mkdir(parents=True, exist_ok=True)
    img.save(str(out_path), "PNG")
    print(f"[avatar] generated: {out_path}")
    return out_path


def generate_avatars():
    """Генерирует аватарки для всех приложений из конфига (если файла нет)."""
    AVATARS_DIR.mkdir(parents=True, exist_ok=True)
    apps = load_apps()
    for app_cfg in apps:
        generate_avatar(app_cfg)
    print(f"[avatar] done: {len(apps)} apps processed")


# ---------------------------------------------------------------------------
# Routes
# ---------------------------------------------------------------------------

@app.route("/")
def index():
    apps = load_apps()
    # Добавляем градиент к каждому приложению
    for app in apps:
        c1, c2 = _hash_gradient(app["name"])
        app["gradient"] = f"linear-gradient(135deg, {c1}, {c2})"
    return render_template("index.html", apps=apps, count=len(apps))


@app.route("/api/apps")
def api_apps():
    return jsonify(load_apps())


@app.route("/static/avatars/<path:filename>")
def avatar(filename):
    return send_from_directory(str(AVATARS_DIR), filename)


# ---------------------------------------------------------------------------
# Entry point
# ---------------------------------------------------------------------------

if __name__ == "__main__":
    generate_avatars()
    app.run(host="0.0.0.0", port=5560, debug=False)
