import crypto from "crypto";
import { prisma } from "../../lib/prisma";
import { logger } from "../../lib/logger";
import { getBot, getBotUsername } from "../../lib/telegram";

function generateRandomCode(): string {
  const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  const bytes = crypto.randomBytes(8);
  let code = "";
  for (let i = 0; i < 8; i++) {
    code += chars[bytes[i] % chars.length];
  }
  return code;
}

function formatPrice(price: number): string {
  return price.toLocaleString("es-AR", {
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
  });
}

export async function generateCode(): Promise<{
  code: string;
  botUsername: string | null;
}> {
  const code = generateRandomCode();

  await prisma.telegramChat.create({
    data: { code },
  });

  return { code, botUsername: getBotUsername() };
}

export async function validateCode(
  chatId: bigint,
  code: string,
): Promise<boolean> {
  const record = await prisma.telegramChat.findUnique({
    where: { code },
  });

  if (!record || record.validatedAt !== null) return false;

  await prisma.telegramChat.deleteMany({
    where: { chatId, validatedAt: { not: null } },
  });

  await prisma.telegramChat.update({
    where: { id: record.id },
    data: {
      chatId,
      validatedAt: new Date(),
    },
  });

  return true;
}

export async function getTelegramStatus(): Promise<{
  botUsername: string | null;
  connected: boolean;
}> {
  const validated = await prisma.telegramChat.findFirst({
    where: { validatedAt: { not: null } },
  });

  return {
    botUsername: getBotUsername(),
    connected: validated !== null,
  };
}

export async function checkAndNotifyBeloMax(): Promise<void> {
  const chat = await prisma.telegramChat.findFirst({
    where: { validatedAt: { not: null } },
    orderBy: { validatedAt: "desc" },
  });

  if (!chat?.chatId) return;

  const bot = getBot();
  if (!bot) return;

  const now = new Date();
  const artHour = ((now.getUTCHours() - 3) % 24 + 24) % 24;
  if (artHour < 8 || artHour >= 20) return;

  const currentQuote = await prisma.quote.findFirst({
    where: { type: "BELO" },
    orderBy: { timeStamp: "desc" },
  });
  if (!currentQuote) return;

  const currentBuy = Number(currentQuote.buy);

  const artOffset = -3;
  const artMs = now.getTime() + artOffset * 3600000;
  const artDate = new Date(artMs);
  const todayStart = new Date(
    Date.UTC(
      artDate.getUTCFullYear(),
      artDate.getUTCMonth(),
      artDate.getUTCDate(),
    ),
  );

  const lastNotified = await prisma.telegramDailyMaxNotification.findUnique({
    where: {
      date_quoteType: {
        date: todayStart,
        quoteType: "BELO",
      },
    },
  });

  const lastNotifiedValue = lastNotified ? Number(lastNotified.maxValue) : 0;

  if (currentBuy <= lastNotifiedValue) return;

  const formattedPrice = formatPrice(currentBuy);
  const message = `BELO alcanzó el máximo del día, la cotización actual es de $${formattedPrice}`;

  try {
    await bot.api.sendMessage(Number(chat.chatId), message);

    await prisma.telegramDailyMaxNotification.upsert({
      where: {
        date_quoteType: {
          date: todayStart,
          quoteType: "BELO",
        },
      },
      create: {
        date: todayStart,
        quoteType: "BELO",
        maxValue: currentBuy,
      },
      update: {
        maxValue: currentBuy,
      },
    });

    logger.info(
      `Telegram BELO max notification sent: $${formattedPrice}`,
    );
  } catch (error) {
    logger.error(error, "Failed to send Telegram BELO max notification");
  }
}
