import { AppTable, db, UserTable } from "@/lib/mastoauth/kysely";
import { MastoAuth } from "@/lib/mastoauth/mastoauth";
import { nanoid } from "nanoid";
import { cookies } from "next/headers";
import { NextRequest, NextResponse } from "next/server";
import { stringify } from "node:querystring";

export async function GET(request: NextRequest) {
  const cookieStore = cookies();
  const instance = cookieStore.get('instance')?.value;
  const code = request.nextUrl.searchParams.get("code");
  if (code == null || instance == null) return new Response('', {
    status: 400
  });
  const mauth = new MastoAuth(instance);

  // Get instance app
  let existingInstanceApp = await db
      .selectFrom('apps')
      .where('apps.instance_domain', '=', instance)
      .selectAll()
      .executeTakeFirst();

  if (existingInstanceApp == null) {
    return  new Response('', {
      status: 500
    });
  }

  // Get temporary user token
  let tUserToken = await mauth.getApplicationToken(existingInstanceApp, code);

  console.log("a", tUserToken);

  if (tUserToken == null) return new Response('', {
    status: 500
  });
  
  // Test for user existence
  let tUserExists;
  if (instance == "github.com")
    tUserExists = await mauth.verifyUser("Bearer " + tUserToken.access_token);
  else tUserExists = await mauth.verifyUser(tUserToken.token_type + " " + tUserToken.access_token);

  console.log(tUserExists);

  if (tUserExists == null) return new Response('', {
    status: 400
  });

  // Check if user is "dangerous"

  const t1ListRequest = await fetch("https://seirdy.one/pb/tier1.csv");
  
  const t1List = await t1ListRequest.text();

  if (t1List == null) return new Response('', {
    status: 500
  });

  // Split lists

  const JSONt1List = t1List.split("\n").slice(2).map(x => x.split(",")[0]);

  // Impersonation check

  if (instance == "discord.com") {
    if (tUserExists.application.id != existingInstanceApp.client_id) return new Response(`URL is invalid`, {
      status: 401
    });
  } else {
    if (!tUserExists.url.includes(instance) && !tUserExists.url.includes(tUserExists.acct)) return new Response(`URL is invalid`, {
      status: 401
    });
  }

  let currentUser;
  if (instance == "discord.com") currentUser = {
    id: nanoid(21),
    instance,
    username: tUserExists.user.username,
    admin: false,
    url: `https://discord.com/users/${tUserExists.user.id}`,
    banned: false, // Discord should be on tier1.
    joined: Date.now()
  } as UserTable;
  else if (instance == "github.com") currentUser = {
    id: nanoid(21),
    instance,
    username: tUserExists.login,
    admin: false,
    url: tUserExists.html_url,
    banned: false, // GitHub should not be on tier1.
    joined: Date.now()
  } as UserTable;
  else currentUser = {
    id: nanoid(21),
    instance,
    username: tUserExists.acct,
    admin: false,
    url: tUserExists.url,
    banned: JSONt1List.includes(instance), // If user's domain is on tier1, start user banned
    joined: Date.now()
  } as UserTable;

  // Get if user already is registered
  let existingUser = await db
      .selectFrom('users')
      .where('users.url', '=', currentUser.url)
      .selectAll()
      .executeTakeFirst();

  if (existingUser == null) {
    try {
      await db.insertInto('users')
        .values(currentUser)
        .returningAll()
        .executeTakeFirstOrThrow();
    } catch (err) {
      return new Response('', {
        status: 500
      });
    }
  } else currentUser = existingUser;

  // "I've seen enough, give token"

  // Clear tokens older than a week

  try {
    await db.deleteFrom('tokens')
      .where('tokens.expires', '<=', Date.now())
      .executeTakeFirstOrThrow();
  } catch (err) {
    // whatever, who cares?
  }

  let currentToken = {
    id: nanoid(21),
    owner: currentUser.id,
    created: Date.now(),
    expires: Date.now() + 604800000 // 1 wk
  };

  // If not expired, give existing token?
  let existingToken = await db
    .selectFrom('tokens')
    .where('tokens.owner', '=', currentUser.id)
    .selectAll()
    .executeTakeFirst();

  if (existingToken != null) currentToken = existingToken;
  else {
    try {
      await db.insertInto('tokens')
        .values(currentToken)
        .returningAll()
        .executeTakeFirstOrThrow();
    } catch (err) {
      return new Response('', {
        status: 500
      });
    }
  }

  cookieStore.set("token", currentToken.id, {
    expires: Date.now() + 604800000
  });
  return Response.redirect(new URL('/jams', request.url));
}