import { Bot, InlineKeyboard } from 'grammy';
import { config } from '../config';
import { prisma } from '../db/client';
import { getRedis, REDIS_KEYS } from '../redis';
import { startNotificationWorker } from './notifier';
import { flushProductStats } from '../stats/productStats';
import { countryLabel, formatUserAgent } from '../geo';

let _bot: Bot | null = null;

export function getBot(): Bot | null {
  return _bot;
}

/** Send a message via the bot (used by the notifier worker) */
async function sendMessage(
  chatId: string,
  text: string,
  extra: object = {},
): Promise<void> {
  if (!_bot) return;
  try {
    await _bot.api.sendMessage(chatId, text, {
      parse_mode: 'HTML',
      ...extra,
    } as Parameters<typeof _bot.api.sendMessage>[2]);
  } catch (err) {
    console.error(`[bot] sendMessage error to ${chatId}:`, (err as Error).message);
  }
}

function isAdmin(chatId: number): boolean {
  return config.tg.adminChatIds.includes(String(chatId));
}

export function startBot(): void {
  if (!config.tg.token) {
    console.log('[bot] TG_BOT_TOKEN not set, Telegram bot disabled');
    return;
  }

  _bot = new Bot(config.tg.token);
  const bot = _bot;

  // ---- Access guard ----
  bot.use(async (ctx, next) => {
    const chatId = ctx.chat?.id;
    if (!chatId || !isAdmin(chatId)) {
      await ctx.reply('⛔ Нет доступа.');
      return;
    }
    await next();
  });

  // ---- /start ----
  bot.command('start', async (ctx) => {
    await ctx.reply(
      '✅ <b>Sinsay Proxy Bot</b>\n\nКоманды:\n' +
        '/stats — статистика за сегодня\n' +
        '/products — самые просматриваемые товары за всё время\n' +
        '/orders — последние 10 заказов\n' +
        '/online — кто сейчас на сайте\n' +
        '/visitor &lt;id&gt; — история визитора',
      { parse_mode: 'HTML' },
    );
  });

  // ---- /stats ----
  bot.command('stats', async (ctx) => {
    try {
      const today = new Date();
      today.setHours(0, 0, 0, 0);

      const [visitors, cartEvents, orders, revenue] = await Promise.all([
        prisma.visitor.count({ where: { createdAt: { gte: today } } }),
        prisma.visitorEvent.count({
          where: { type: 'cart.add', createdAt: { gte: today } },
        }),
        prisma.order.count({ where: { createdAt: { gte: today } } }),
        prisma.order.aggregate({
          where: { createdAt: { gte: today }, status: { not: 'cancelled' } },
          _sum: { total: true },
        }),
      ]);

      await ctx.reply(
        `📊 <b>Статистика за сегодня</b>\n\n` +
          `👥 Новых визиторов: <b>${visitors}</b>\n` +
          `🛒 Добавлений в корзину: <b>${cartEvents}</b>\n` +
          `💰 Заказов: <b>${orders}</b>\n` +
          `💵 Выручка: <b>${(revenue._sum.total ?? 0).toFixed(2)} PLN</b>`,
        { parse_mode: 'HTML' },
      );
    } catch (err) {
      await ctx.reply('❌ Ошибка получения статистики: ' + (err as Error).message);
    }
  });

  // ---- /products ----
  bot.command('products', async (ctx) => {
    try {
      await flushProductStats();
      const products = await prisma.productStat.findMany({
        take: 15,
        orderBy: [{ totalViews: 'desc' }, { lastSeenAt: 'desc' }],
      });

      if (products.length === 0) {
        await ctx.reply('Статистики по товарам пока нет.');
        return;
      }

      const rows = products
        .map((p, idx) => {
          const name = esc(p.name.length > 55 ? `${p.name.slice(0, 52)}...` : p.name);
          return (
            `${idx + 1}. <b>${name}</b>\n` +
            `   👁 ${p.totalViews} · 👤 ~${p.uniqueVisitors} · <code>${esc(p.productId)}</code>\n` +
            `   ${esc(p.url)}`
          );
        })
        .join('\n\n');

      await ctx.reply(`📦 <b>Топ товаров за всё время</b>\n\n${rows}`, {
        parse_mode: 'HTML',
      });
    } catch (err) {
      await ctx.reply('❌ Ошибка получения статистики товаров: ' + (err as Error).message);
    }
  });

  // ---- /orders ----
  bot.command('orders', async (ctx) => {
    try {
      const orders = await prisma.order.findMany({
        take: 10,
        orderBy: { createdAt: 'desc' },
        include: { items: true },
      });

      if (orders.length === 0) {
        await ctx.reply('Заказов пока нет.');
        return;
      }

      for (const order of orders) {
        const statusEmoji = order.status === 'done' ? '✅' : order.status === 'cancelled' ? '❌' : '🆕';
        const kb = new InlineKeyboard()
          .text('✅ Обработан', `order:${order.id}:done`)
          .text('❌ Отмена', `order:${order.id}:cancel`);

        await ctx.reply(
          `${statusEmoji} <b>Заказ #${order.id}</b> · ${order.total.toFixed(2)} ${order.currency}\n` +
            `👤 ${esc(order.name)} · 📞 ${esc(order.phone)}\n` +
            `📍 ${esc(order.city)}\n` +
            `📦 ${order.items.length} товара\n` +
            `🕐 ${formatDate(order.createdAt)}`,
          { parse_mode: 'HTML', reply_markup: order.status === 'new' ? kb : undefined },
        );
      }
    } catch (err) {
      await ctx.reply('❌ Ошибка: ' + (err as Error).message);
    }
  });

  // ---- /online ----
  bot.command('online', async (ctx) => {
    try {
      const redis = getRedis();
      const cutoff = Date.now() - config.onlineWindowSec * 1000;
      const count = await redis.zcount(REDIS_KEYS.onlineVisitors, cutoff, '+inf');
      await ctx.reply(
        `🟢 Сейчас на сайте: <b>${count}</b> уникальных визиторов\n` +
          `(активность за последние ${config.onlineWindowSec / 60} мин)`,
        { parse_mode: 'HTML' },
      );
    } catch (err) {
      await ctx.reply('❌ Ошибка: ' + (err as Error).message);
    }
  });

  // ---- /visitor <id> ----
  bot.command('visitor', async (ctx) => {
    const shortId = ctx.match?.trim();
    if (!shortId) {
      await ctx.reply('Использование: /visitor <первые 8 символов id>');
      return;
    }
    try {
      const visitors = await prisma.visitor.findMany({
        where: { uuid: { startsWith: shortId } },
        include: { events: { orderBy: { createdAt: 'asc' }, take: 20 } },
      });
      if (visitors.length === 0) {
        await ctx.reply('Визитор не найден.');
        return;
      }
      const v = visitors[0];
      const events = v.events
        .map((e) => `  ${formatDate(e.createdAt)} · <code>${e.type}</code>`)
        .join('\n');
      await ctx.reply(
        `📋 <b>Визитор #${v.uuid.slice(0, 8)}</b>\n` +
          `🌐 <code>${esc(v.ip)}</code>\n` +
          `🌍 ${esc(countryLabel(v.country, v.city))}\n` +
          `🖥 ${esc(formatUserAgent(v.userAgent))}\n` +
          (v.referer ? `↩️ <code>${esc(v.referer)}</code>\n` : '') +
          (v.landingUrl ? `📄 <code>${esc(v.landingUrl)}</code>\n` : '') +
          `🕐 Первый визит: ${formatDate(v.createdAt)}\n\n` +
          `<b>События:</b>\n${events || '  нет событий'}`,
        { parse_mode: 'HTML' },
      );
    } catch (err) {
      await ctx.reply('❌ Ошибка: ' + (err as Error).message);
    }
  });

  // ---- Inline callback buttons ----
  bot.callbackQuery(/^order:(\d+):(done|cancel)$/, async (ctx) => {
    const orderId = parseInt(ctx.match[1]);
    const action = ctx.match[2] as 'done' | 'cancel';
    const newStatus = action === 'done' ? 'done' : 'cancelled';

    try {
      await prisma.order.update({
        where: { id: orderId },
        data: { status: newStatus },
      });
      const emoji = action === 'done' ? '✅' : '❌';
      await ctx.editMessageText(
        (ctx.msg?.text ?? '') + `\n\n${emoji} Статус обновлён: <b>${newStatus}</b>`,
        { parse_mode: 'HTML' },
      );
      await ctx.answerCallbackQuery(`Заказ #${orderId} → ${newStatus}`);
    } catch (err) {
      await ctx.answerCallbackQuery('Ошибка: ' + (err as Error).message);
    }
  });

  bot.callbackQuery(/^visitor:(.+):history$/, async (ctx) => {
    const shortId = ctx.match[1];
    await ctx.answerCallbackQuery();
    // Re-use the /visitor command logic
    const visitors = await prisma.visitor.findMany({
      where: { uuid: { startsWith: shortId } },
      include: { events: { orderBy: { createdAt: 'asc' }, take: 20 } },
    });
    if (visitors.length === 0) {
      await ctx.reply('Визитор не найден.');
      return;
    }
    const v = visitors[0];
    const events = v.events
      .map((e) => `  ${formatDate(e.createdAt)} · <code>${e.type}</code>`)
      .join('\n');
    await ctx.reply(
      `📋 <b>История визитора #${v.uuid.slice(0, 8)}</b>\n${events || '  нет событий'}`,
      { parse_mode: 'HTML' },
    );
  });

  // ---- Support chat handlers live in tg/supportBot.ts ----

  // Start the notification worker linked to this bot
  startNotificationWorker(sendMessage);

  bot.start({ onStart: () => console.log('[bot] Telegram bot polling started') });
}

function esc(text?: string | null): string {
  if (!text) return '';
  return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}

function formatDate(d: Date): string {
  return d.toLocaleString('ru-RU', { timeZone: 'Europe/Warsaw' });
}
