import { env } from 'bun';
import homepage from './index.html';
import robotsTxt from './static/robots.txt';
import sitemapTxt from './static/sitemap.txt';
// @ts-ignore ts2307
import icon from './static/favicon.png' with { type: 'file' };
const favicon = await Bun.file(icon).bytes();
const development = env.NODE_ENV !== 'production';
import { randomUUIDv7 } from 'bun';
import ptApi from './server/pt-api';

declare global {
  var loginTokens: Set<string>;
}

if (!globalThis.loginTokens) {
  globalThis.loginTokens = new Set<string>();
}

const authCookie = 'pt-auth';

let entriesCache = '';
let entriesCacheTime = 0;
const entriesCacheTimeLimit = 1000 * 15;

async function getEntriesCached() {
  if (entriesCacheTime + entriesCacheTimeLimit < Date.now()) {
    const data = await ptApi.query();
    entriesCache = JSON.stringify(data);
    entriesCacheTime = Date.now();
  }
  return entriesCache;
}

Bun.serve({
  routes: {
    '/': homepage,
    '/robots.txt': new Response(robotsTxt, {
      headers: { 'Content-Type': 'text/plain' },
    }),
    '/sitemap.txt': new Response(sitemapTxt, {
      headers: { 'Content-Type': 'text/plain' },
    }),
    '/favicon.ico': new Response(favicon, {
      headers: { 'Content-Type': 'image/png' },
    }),
    '/health': new Response('OK'),
    '/api/entries': {
      async GET(req) {
        if (!isLoggedIn(req)) return unauthorizedResp();

        return new Response(await getEntriesCached(), {
          headers: {
            'Content-Type': 'application/json'
          }
        });
      },
    },
    '/auth/logout': {
      async POST() {
        return new Response('Logout successful', { headers: logoutHeaders() });
      },
    },
    '/auth/login': {
      async POST(req) {
        const json = await req.json();
        const data = json as Record<string, any>;
        const email = data.email;
        const password = data.password;

        if (
          typeof email !== 'string' ||
          typeof password !== 'string' ||
          email.length < 3 ||
          password.length === 0
        ) {
          return new Response('Missing email or password', { status: 400 });
        }

        await new Promise((resolve) => setTimeout(resolve, 100));

        if (email === env.EMAIL && password === env.PASSWORD) {
          let token = randomUUIDv7('base64url');
          while (globalThis.loginTokens.has(token)) {
            // generate a new token if it already exists
            // this is unlikely to happen, but just in case
            token = randomUUIDv7();
          }

          const cookie = new Bun.Cookie({
            name: authCookie,
            value: token,
            path: '/',
            maxAge: 60 * 60 * 24 * 31,
            secure: true,
            sameSite: 'strict',
          });

          const headers = new Headers({ 'Set-Cookie': cookie.toString() });

          globalThis.loginTokens.add(token);

          setTimeout(getEntriesCached, 1);

          return new Response('Login successful', { headers });
        }

        await new Promise((resolve) => setTimeout(resolve, 900));

        return new Response('Incorrect email or password', {
          status: 400,
        });
      },
    },
  },
  development,
  reusePort: true,
  // async fetch(req, server) {
  //   return new Response("Not found", { status: 404 });
  // },
});

function isLoggedIn(req: Request) {
  const cookie = new Bun.CookieMap(req.headers.get('cookie') || '');
  const token = cookie.get(authCookie);

  if (!token) {
    return false;
  }

  return globalThis.loginTokens.has(token);
}

function logoutHeaders() {
  return new Headers({
    'Set-Cookie': new Bun.Cookie({
      name: authCookie,
      path: '/',
      maxAge: -1,
      secure: true,
      sameSite: 'strict',
    }).toString(),
  });
}

function unauthorizedResp() {
  return new Response('Unauthorized', { status: 401, headers: logoutHeaders() });
}