import express, { Request } from "express";
import { getDateForWeekIndex, getData, getRestaurantMenu, getToday, initIfNeeded } from "../service";
import { formatDate, getDayOfWeekIndex } from "../utils";
import getStorage from "../storage";
import { getWebsocket } from "../websocket";
import { getLogin } from "../auth";
import { parseToken } from "../utils";
import webpush from 'web-push';

const router = express.Router();
const storage = getStorage();
const ENVIRONMENT = process.env.NODE_ENV ?? 'production';

// Seznam náhodných jmen pro generování mock dat
const MOCK_NAMES = [
    'Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Filip', 'Gita', 'Honza',
    'Ivana', 'Jakub', 'Kamila', 'Lukáš', 'Markéta', 'Nikola', 'Ondřej',
    'Petra', 'Quido', 'Radek', 'Simona', 'Tomáš', 'Ursula', 'Viktor',
    'Wanda', 'Xaver', 'Yvona', 'Zdeněk', 'Aneta', 'Boris', 'Cecílie', 'Daniel'
];

// Volby stravování pro mock data
const LUNCH_CHOICES = [
    'SLADOVNICKA',
    'TECHTOWER',
    'ZASTAVKAUMICHALA',
    'SENKSERIKOVA',
    'OBJEDNAVAM',
    'NEOBEDVAM',
    'ROZHODUJI',
];

// Restaurace s menu
const RESTAURANTS_WITH_MENU = [
    'SLADOVNICKA',
    'TECHTOWER',
    'ZASTAVKAUMICHALA',
    'SENKSERIKOVA',
];

/**
 * Middleware pro kontrolu DEV režimu
 */
function requireDevMode(req: any, res: any, next: any) {
    if (ENVIRONMENT !== 'development' && ENVIRONMENT !== 'test') {
        return res.status(403).json({ error: 'Tento endpoint je dostupný pouze ve vývojovém režimu' });
    }
    next();
}

router.use(requireDevMode);

/**
 * Vygeneruje mock data pro testování.
 */
router.post("/generate", async (req: Request<{}, any, any>, res, next) => {
    try {
        const dayIndex = req.body?.dayIndex ?? getDayOfWeekIndex(getToday());
        const count = req.body?.count ?? Math.floor(Math.random() * 16) + 5; // 5-20

        if (dayIndex < 0 || dayIndex > 4) {
            return res.status(400).json({ error: 'Neplatný index dne (0-4)' });
        }

        const date = getDateForWeekIndex(dayIndex);
        await initIfNeeded(date);

        const dateKey = formatDate(date);
        const data = await storage.getData<any>(dateKey);

        // Získání menu restaurací pro vybraný den
        const menus: { [key: string]: any } = {};
        for (const restaurant of RESTAURANTS_WITH_MENU) {
            const menu = await getRestaurantMenu(restaurant as any, date);
            if (menu?.food?.length) {
                menus[restaurant] = menu.food;
            }
        }

        // Vygenerování náhodných uživatelů
        const usedNames = new Set<string>();
        for (let i = 0; i < count && usedNames.size < MOCK_NAMES.length; i++) {
            // Vybereme náhodné jméno, které ještě nebylo použito
            let name: string;
            do {
                name = MOCK_NAMES[Math.floor(Math.random() * MOCK_NAMES.length)];
            } while (usedNames.has(name));
            usedNames.add(name);

            // Vybereme náhodnou volbu stravování
            const choice = LUNCH_CHOICES[Math.floor(Math.random() * LUNCH_CHOICES.length)];

            // Inicializace struktury pro volbu
            data.choices[choice] ??= {};
            
            const userChoice: any = {
                trusted: false,
                selectedFoods: [],
            };

            // Pokud má restaurace menu, vybereme náhodné jídlo
            if (RESTAURANTS_WITH_MENU.includes(choice) && menus[choice]?.length) {
                const foods = menus[choice];
                // Vybereme náhodné jídlo (ne polévku)
                const mainFoods = foods.filter((f: any) => !f.isSoup);
                if (mainFoods.length > 0) {
                    const randomFoodIndex = foods.indexOf(mainFoods[Math.floor(Math.random() * mainFoods.length)]);
                    userChoice.selectedFoods = [randomFoodIndex];
                }
            }

            data.choices[choice][name] = userChoice;
        }

        await storage.setData(dateKey, data);

        // Odeslat aktualizovaná data přes WebSocket
        const clientData = await getData(date);
        getWebsocket().emit("message", clientData);

        res.status(200).json({ success: true, count: usedNames.size, dayIndex });
    } catch (e: any) {
        next(e);
    }
});

/**
 * Smaže všechny volby pro daný den.
 */
router.post("/clear", async (req: Request<{}, any, any>, res, next) => {
    try {
        const dayIndex = req.body?.dayIndex ?? getDayOfWeekIndex(getToday());

        if (dayIndex < 0 || dayIndex > 4) {
            return res.status(400).json({ error: 'Neplatný index dne (0-4)' });
        }

        const date = getDateForWeekIndex(dayIndex);
        await initIfNeeded(date);

        const dateKey = formatDate(date);
        const data = await storage.getData<any>(dateKey);

        // Vymažeme všechny volby i aktivní pizza day
        data.choices = {};
        delete data.pizzaDay;

        await storage.setData(dateKey, data);

        // Odeslat aktualizovaná data přes WebSocket
        const clientData = await getData(date);
        getWebsocket().emit("message", clientData);

        res.status(200).json({ success: true, dayIndex });
    } catch (e: any) {
        next(e);
    }
});

/** Vrátí obsah push reminder registry (pro ladění). */
router.get("/pushRegistry", async (_req, res, next) => {
    try {
        const registry = await storage.getData<any>('push_reminder_registry') ?? {};
        const sanitized = Object.fromEntries(
            Object.entries(registry).map(([login, entry]: [string, any]) => [
                login,
                { time: entry.time, endpoint: entry.subscription?.endpoint?.slice(0, 60) + '…' }
            ])
        );
        res.status(200).json(sanitized);
    } catch (e: any) { next(e) }
});

/** Okamžitě odešle test push notifikaci přihlášenému uživateli (pro ladění). */
router.post("/testPush", async (req, res, next) => {
    const login = getLogin(parseToken(req));
    try {
        const registry = await storage.getData<any>('push_reminder_registry') ?? {};
        const entry = registry[login];
        if (!entry) {
            return res.status(404).json({ error: `Uživatel ${login} nemá uloženou push subscription. Nastav připomínku v nastavení.` });
        }
        const publicKey = process.env.VAPID_PUBLIC_KEY;
        const privateKey = process.env.VAPID_PRIVATE_KEY;
        const subject = process.env.VAPID_SUBJECT;
        if (!publicKey || !privateKey || !subject) {
            return res.status(503).json({ error: 'VAPID klíče nejsou nastaveny' });
        }
        webpush.setVapidDetails(subject, publicKey, privateKey);
        await webpush.sendNotification(
            entry.subscription,
            JSON.stringify({ title: 'Luncher test', body: 'Push notifikace fungují!', login })
        );
        res.status(200).json({ ok: true });
    } catch (e: any) { next(e) }
});

export default router;
