import { Markup, Telegraf } from "telegraf";
import { message } from "telegraf/filters";
import { AppDataSource } from "./data_source.js";
import { User } from "./models/User.js";
import Logging from "./log.js";
import { Feed } from "./models/Feed.js";


const bot = new Telegraf(process.env.TG_TOKEN)

function botHandler<T>(handler: (ctx: T) => Promise<any>) {
   return async (ctx: T) => {
      try {
         await handler(ctx);
      } catch (err) {
         Logging.error(err);
         (ctx as any).reply("An error occured while processing your request.");
      }
   }
}

bot.start(botHandler(async ctx => {
   await ctx.reply("Send some RSS Feed URLs to get started.");
}));

bot.command("list", botHandler(async (ctx) => {

   let user = await AppDataSource.manager.findOne(User, {
      where: {
         chatid: ctx.chat.id
      },
      relations: {
         feeds: true,
      }
   })

   if (!user) {
      ctx.reply("You have no feeds yet.");
   } else {
      ctx.reply("You are currently subscribed to: \n" + user.feeds.map(feed => feed.url).join("\n"));
   }
}));

bot.command("delete", botHandler(async ctx => {
   let user = await AppDataSource.manager.findOne(User, {
      where: {
         chatid: ctx.chat.id
      },
      relations: {
         feeds: true,
      }
   })

   if (!user || user.feeds.length === 0) {
      ctx.reply("You have no feeds yet.");
   } else {

      ctx.replyWithHTML("Select a feed to delete:", {
         ...Markup.inlineKeyboard(user.feeds.map(feed => Markup.button.callback(feed.url, "delete:" + feed.id)))
      })
   }
}));

bot.on("callback_query", botHandler(async ctx => {
   Logging.info("Callback Query:");
   Logging.info(ctx.callbackQuery);

   const remove_options = () => {
      ctx.editMessageReplyMarkup({
         inline_keyboard: []
      })
   }

   let data = (ctx.callbackQuery as any).data;
   if (!data) {
      ctx.answerCbQuery("Invalid data");
      remove_options();
      return
   }

   let [action, id] = data.split(":");
   if (!action || !id) {
      ctx.answerCbQuery("Invalid data");
      remove_options();
      return
   }

   if (action === "delete") {
      let user = await AppDataSource.manager.findOne(User, {
         where: {
            chatid: ctx.chat.id
         },
         relations: {
            feeds: true,
         }
      });

      if (user) {
         user.feeds = user.feeds.filter(feed => feed.id !== Number(id));
         await AppDataSource.manager.save(user);
      }
   } else {
      ctx.answerCbQuery("Invalid action");
      remove_options();
      return
   }

   ctx.answerCbQuery("Success");
   remove_options();
}));

bot.on(message("text", "entities"), botHandler(async ctx => {
   let user = await AppDataSource.manager.findOne(User, {
      where: {
         chatid: ctx.chat.id
      }
   });

   if (!user) {
      user = AppDataSource.manager.create(User, {
         chatid: ctx.chat.id,
         feeds: [],
      })

      await AppDataSource.manager.save(user);
   }


   Logging.debug("Received message:", ctx.message);
   const urls = ctx.message.entities.filter(e => e.type === "url").map(e => ctx.message.text.slice(e.offset, e.offset + e.length));
   Logging.debug("URLs:", urls);

   for (let url of urls) {
      let normalized = new URL(url).href;
      Logging.debug("Normalized URL:", normalized);

      let feed = await AppDataSource.manager.findOne(Feed, {
         where: {
            url: normalized
         },
         relations: {
            subscriber: true,
         }
      });

      if (feed) {
         feed.subscriber.push(user);
         await AppDataSource.manager.save(feed);
      } else {
         feed = AppDataSource.manager.create(Feed, {
            oldEntries: [],
            subscriber: [user],
            url: normalized,
         })
         await AppDataSource.manager.save(feed);
      }
   }

   await ctx.reply("Added feeds.");
}));

export default bot;