import express from "express";
import { config } from "dotenv";
import path from "path";
import SQLite from 'better-sqlite3';
import { Kysely, SqliteDialect } from 'kysely';
import { nanoid } from "nanoid";
import { JSDOM } from "jsdom";

const __dirname = import.meta.dirname;

const rawDB = new SQLite('abtmtr.db');

const db = new Kysely({
  dialect: new SqliteDialect({
    database: rawDB,
  })
});

rawDB.exec(`CREATE TABLE IF NOT EXISTS blurbs( 'id' TEXT, 'site' TEXT, 'blurb' TEXT, 'verified' INTEGER, 'time' INTEGER );`);

const app = express();

app.set('view engine', 'ejs');
app.use('/assets', express.static('assets'));
app.set('views', path.join(__dirname, "views", "pages"));

app.locals = {
  visibility: [
    "Backend",
    "Personal",
    "Friends-only",
    "Login-only",
    "Public"
  ]
}

config();

app.use(async (req, res, next) => {
  const buttonsJson = await fetch("https://cdn.abtmtr.link/site_content/buttons.json")
    .catch(() => res.status(500).send())
    .then((res) => res.json())
    .catch(() => res.status(500).send());
  const followingJson = await fetch("https://cdn.abtmtr.link/site_content/following.json")
    .catch(() => res.status(500).send())
    .then((res) => res.json())
    .catch(() => res.status(500).send());
  app.locals.buttons = buttonsJson;
  app.locals.following = followingJson;
  app.locals.randomAd = Math.round(Math.random());
  next();
})

app.get('/', async (req, res) => {
  const statusesJson = await fetch("https://cdn.abtmtr.link/site_content/v13/statuses.json")
    .catch(() => res.status(500).send())
    .then((res) => res.json());

  res.render('index', {
    statuses: statusesJson
  });
})

app.get('/services', async (req, res) => {
  const servicesJson = await fetch("https://cdn.abtmtr.link/site_content/v13/services.json")
    .catch(() => res.status(500).send())
    .then((res) => res.json());

  res.render('services/index', { services: servicesJson });
});

app.get('/computers', async (req, res) => {
  const computersJson = await fetch("https://cdn.abtmtr.link/site_content/v13/computers.json")
    .catch(() => res.status(500).send())
    .then((res) => res.json());

  res.render('computers/index', { computers: computersJson });
});

app.get('/links', async (req, res) => {
  const linksJson = await fetch("https://cdn.abtmtr.link/site_content/v13/links.json")
    .catch(() => res.status(500).send())
    .then((res) => res.json());

  res.render('links/index', {
    links: linksJson
  });
});

app.get('/matkap', (req, res) => {
  res.render('matkap/index');
});

app.get('/about', (req, res) => {
  res.render('about/index');
});

app.get('/blurbs', async (req, res) => {
  const data = await db
    .selectFrom('blurbs')
    .selectAll()
    .where('verified', '=', 1)
    .orderBy('time', "desc")
    .execute();
  res.render('blurbs/index', { data });
});

// brbrleibbghbelsbbsbuuebbuubsubss
async function cleanupBlurbles() {
  const timeNow = Date.now() - 86400000;
  await db
    .deleteFrom('blurbs')
    .where('time', '<', timeNow)
    .where('verified', '=', 0)
    .execute()
}

app.get('/blurbs/send', async (req, res) => {
  const body = req.query;
  const errors = [];

  if (body.site == null) errors.push("Site domain required");
  else {
    const status = await fetch(body.site).then(x => x.status).catch(_ => _);
    if (status != 200) errors.push("Site must be online");
  }
  if (body.text == null) errors.push("Blurb text required");
  else {
    if (body.text.length < 1) errors.push("Blurb text must not be blank");
    if (body.text.length > 140) errors.push("Blurb text must not exceed 140 characters");
  }

  if (errors.length > 0) return res.status(400).json({
    error: "Bad Request",
    message: errors.join(", ")
  });

  const postId = nanoid(32);

  try {
    await db.insertInto('blurbs')
      .values({
        id: postId,
        site: body.site,
        blurb: body.text,
        verified: 0,
        time: Date.now()
      })
      .executeTakeFirstOrThrow();
  } catch (err) {
    console.log(err)
    return res.status(500).send('Internal Server Error');
  }

  cleanupBlurbles();

  res.render('blurbs/sent', { id: postId });
});

app.get('/blurbs/check', async (req, res) => {
  const body = req.query;
  const blurbFromId = await db
    .selectFrom('blurbs')
    .selectAll()
    .where('id', '=', body.id)
    .executeTakeFirst();

  if (blurbFromId == null) return res.redirect("/blurbs/");

  const site = await fetch(blurbFromId.site).then(x => x.text()).catch(_ => _);
  const dom = new JSDOM(site);
  const relationLink = dom.window.document.querySelector(
    `[rel=me][href="https://abtmtr.link/blurbs/#${blurbFromId.id}"]`
  );
  if (relationLink != null) await db
    .updateTable('blurbs')
    .set({
      verified: 1
    })
    .where('id', '=', body.id)
    .executeTakeFirst();
  else {
    await db
      .updateTable('blurbs')
      .set({
        verified: 0
      })
      .where('id', '=', body.id)
      .executeTakeFirst();
  }

  cleanupBlurbles();

  res.redirect("/blurbs/");
});

app.get("/favicon.ico", (req, res) => {
  res.redirect("https://cdn.abtmtr.link/site_content/favicon.ico")
})

app.listen(process.env.PORT, () => {
  const url = new URL("http://localhost/");
  url.port = process.env.PORT;
  console.log(`Example app listening on ${url.toString()}`);
});