const db = require("../config/db");
const Notification = require("../utils/notification");
const sharp = require('sharp');
const TelegramBot = require("node-telegram-bot-api");

const util = require('util');
const dbAll = util.promisify(db.all).bind(db);
const dbRun = util.promisify(db.run).bind(db);

const TOKEN = process.env.TELEGRAM_TOKEN;
const STAND_CHAT_ID = process.env.STAND_CHAT_ID;

const bot = new TelegramBot(TOKEN, { polling: false });


class Stands {
    async check_add() {
        const sqlStands = `
            SELECT id
            FROM stand_list
            WHERE status = '1'
            ORDER BY id
        `;

        db.all(sqlStands, (err, stands) => {
            if (err) {
                console.error('DB error:', err.message);
                return;
            }

            if (!stands.length) {
                console.log('There are no active stands');
                return;
            }

            const dateNow = Date.now();

            const sqlSchedule = `
                SELECT 1
                FROM stand_schedule
                WHERE stand_id = ?
                AND date >= ?
                LIMIT 1
            `;

            let checked = 0;
            let emptyStands = 0;

            stands.forEach(stand => {
                db.get(sqlSchedule, [stand.id, dateNow], (err, row) => {
                    if (err) {
                        console.error('Schedule error:', err.message);
                        return;
                    }

                    if (!row) emptyStands++;

                    checked++;

                    if (checked === stands.length) {
                        console.log('Empty stands:', emptyStands);

                        if (emptyStands > 0) {
                            Notification.sendStandAdd({
                                title: 'Додайте нові дні служіння',
                                body: `${emptyStands} з ${stands.length} стендів потребують додавання днів служіння.`,
                                page: '/stand'
                            });
                        }
                    }
                });
            });
        });
    }

    async check_entries() {
        try {
            const today = new Date();
            today.setHours(0, 0, 0, 0);

            // 1. Отримуємо вісників і одразу робимо Map для швидкого пошуку
            const sheeps = await dbAll(`SELECT id, name FROM sheeps`);
            if (!sheeps.length) return console.log('There are no sheeps');

            const sheepMap = new Map(sheeps.map(s => [s.id, s.name]));

            const startTomorrow = today.getTime() + 86400000;
            const startDayAfterTomorrow = today.getTime() + 86400000 * 2;

            const sqlStands = `
                SELECT 
                    stand_schedule.*,
                    (SELECT stand_list.title FROM stand_list WHERE stand_list.id = stand_schedule.stand_id) AS title
                FROM 
                    stand_schedule 
                WHERE 
                    stand_schedule.date >= ? AND stand_schedule.date < ? 
                ORDER BY 
                    stand_schedule.stand_id
            `;

            const schedule = await dbAll(sqlStands, [startTomorrow, startDayAfterTomorrow]);
            if (!schedule.length) return console.log('No active schedule');

            // 2. Угруповання даних (Transform)
            const standsData = schedule.reduce((acc, item) => {
                if (!acc[item.stand_id]) {
                    acc[item.stand_id] = { id: item.stand_id, title: item.title || `Стенд ${sId}`, hours: {}, maxSheepIdx: 0, date: item.date };
                }
                if (!acc[item.stand_id].hours[item.hour]) {
                    acc[item.stand_id].hours[item.hour] = {};
                }
                acc[item.stand_id].hours[item.hour][item.number_sheep] = item.sheep_id;
                acc[item.stand_id].maxSheepIdx = Math.max(acc[item.stand_id].maxSheepIdx, item.number_sheep);
                return acc;
            }, {});

            // 3. Генерація
            for (const standId in standsData) {
                const data = standsData[standId];
                const title = data.title;
                const sortedHours = Object.keys(data.hours).map(Number).sort((a, b) => a - b);

                // Визначаємо крок (мінімальна різниця між годинником або 1)
                let step = 1;
                if (sortedHours.length > 1) {
                    step = sortedHours[1] - sortedHours[0];
                }

                const sheepIdsMatrix = sortedHours.map(h => {
                    const row = [];
                    for (let i = 0; i <= data.maxSheepIdx; i++) {
                        row.push(data.hours[h][i] || null);
                    }
                    return row;
                });

                const formattedDate = new Date(data.date).toLocaleDateString('ru-RU');

                const result = await generateSchedule({
                    title: title,
                    date: formattedDate,
                    options: {
                        start: sortedHours[0],
                        quantity: data.maxSheepIdx + 1,
                        step: step
                    },
                    sheep_ids: sheepIdsMatrix,
                    sheepMap // Передаємо Map для імен
                });

                if (result && result.buffer) {
                    try {
                        let isNotFull = result.isNotFull ? '\n\n✏️ Ще є вільні місця, встигніть записатись' : '';

                        // 1. Надсилаємо нове фото
                        const sentMessage = await bot.sendPhoto(STAND_CHAT_ID, result.buffer, {
                            caption: `📍 *${title}*\n📅 ${formattedDate}${isNotFull}`,
                            parse_mode: 'Markdown'
                        }, {
                            filename: result.fileName,
                            contentType: 'image/png'
                        });

                        // 2. Зберігаємо ID нового повідомлення у базі
                        await dbRun(
                            `INSERT INTO sent_messages (last_message_id, created_at) VALUES (?, ?)`, [sentMessage.message_id, Date.now()]
                        );

                        console.log(`✅ Обновлено: ${title}`);

                    } catch (err) {
                        console.error('Помилка відправки в Telegram:', err.message);
                    }
                }
            }
        } catch (err) {
            console.error('Logic error:', err);
        }
    }
}


// Генерування зображення графіка
async function generateSchedule({
    title, date, options, sheep_ids, sheepMap
}) {
    const { start, step, quantity } = options;
    const rowsCount = sheep_ids.length;

    const rowHeight = 50;
    const timeWidth = 120;
    const gap = 10;
    const padding = 10;

    const totalWidth = 200 + (200 * quantity);
    const headerHeight = 85;
    const totalHeight = 136 + (rowHeight * (rowsCount - 1));

    const mainRectWidth = totalWidth - (padding * 2);
    const availableForBlocks = mainRectWidth - timeWidth - 5;
    const blockWidth = (availableForBlocks - (gap * (quantity - 1))) / quantity;

    let isNotFull = false; 

    const formatTime = (h) => {
        const hh = Math.floor(h).toString().padStart(2, '0');
        const mm = (h % 1 * 60).toString().padStart(2, '0');
        return `${hh}:${mm}`;
    };

    let rowsSvg = '';
    sheep_ids.forEach((rowSheepIds, i) => {
        const y = headerHeight + (i * rowHeight);
        const hStart = formatTime(start + (i * step));
        const hEnd = formatTime(start + ((i + 1) * step));
        const isEven = i % 2 === 0;

        // Фон рядка
        rowsSvg += `<rect x="${padding}" y="${y}" width="${totalWidth - padding * 2}" height="40" rx="8" fill="${isEven ? '#fbfbfb' : '#e7e7e1'}" />`;

        // Текст часу
        rowsSvg += `<text x="${padding + 7}" y="${y + 27}" font-family="Roboto Mono" font-size="15" fill="#313131">${hStart}-${hEnd}</text>`;

        // Блоки з іменами
        rowSheepIds.forEach((id, j) => {
            const x = padding + timeWidth + (j * (blockWidth + gap));
            const name = sheepMap.get(id) || '';
            if(!sheepMap.get(id)) isNotFull = true; // Якщо є вільне місце

            rowsSvg += `
                <g>
                    <rect x="${x}" y="${y + 5}" width="${blockWidth}" height="30" rx="5" fill="${isEven ? '#e7e7e1' : '#fbfbfb'}" />
                    <text x="${x + 5}" y="${y + 25}" font-family="Roboto Mono" font-size="15" fill="#313131">${name}</text>
                </g>`;
        });
    });

    const finalSvg = `
        <svg width="${totalWidth * 2}" height="${totalHeight * 2}" viewBox="0 0 ${totalWidth} ${totalHeight}" xmlns="http://www.w3.org/2000/svg">
            <rect height="${totalHeight}" width="${totalWidth}" fill="#e7e7e1"/>
            <text font-weight="bold" text-anchor="middle" font-family="'Roboto Mono'" font-size="24" y="52" x="${totalWidth / 2}" fill="#313131">
                ${date} • ${title}
            </text>
            ${rowsSvg}
        </svg>`;

    try {
        const buffer = await sharp(Buffer.from(finalSvg))
            .png()
            .toBuffer();

        return { buffer, fileName: `${title}_${date}.png`, isNotFull };
    } catch (e) {
        console.error('Sharp error:', e);
        return null;
    }
}

module.exports = new Stands();