import { error, json } from "@sveltejs/kit";
import { BASE_DOMAIN, MAX_SATS_RECEIVE, MIN_SATS_RECEIVE } from "$lib/config";
import {
  isNpub,
  userExists,
  userExistsOrNpub,
  validateLightningInvoiceAmount,
} from "$lib";
import { getDb } from "$lib/database";
import { nip19 } from "nostr-tools";

interface LNURLPayRequest {
  callback: string;
  minSendable: number;
  maxSendable: number;
  metadata: string;
  tag: "payRequest";
}

/** @type {import('./$types').RequestHandler} */
export async function GET({ params, url, request }) {
  const { username } = params;
  const amount = url.searchParams.get("amount");

  if (!/^[a-z0-9\-_.]+$/.test(username)) {
    throw error(400, "Invalid username format");
  }

  if (!(await userExistsOrNpub(username))) {
    throw error(404, "User not found");
  }

  if (
    amount && !validateLightningInvoiceAmount(amount, { isMillisats: true })
  ) {
    throw error(
      400,
      `Amount must be between ${MIN_SATS_RECEIVE} and ${MAX_SATS_RECEIVE} millisats`,
    );
  }

  const domain = request.headers.get("host") || new URL(BASE_DOMAIN).host;
  const identifier = `${username}@${domain}`;

  const response: LNURLPayRequest = {
    callback: `https://${domain}/.well-known/lnurl-pay/callback/${
      encodeURIComponent(
        username,
      )
    }`,
    minSendable: MIN_SATS_RECEIVE * 1000,
    maxSendable: MAX_SATS_RECEIVE * 1000,
    metadata: JSON.stringify([
      ["text/plain", `Pay ${username}`],
      ["text/identifier", identifier],
    ]),
    tag: "payRequest",
  };

  return json(response);
}

/** @type {import('./$types').RequestHandler} */
export async function POST({ params, url, request }) {
  // TODO: creating a username should cost a small amount of sats
  // 105k sats for 1 character names
  //  63k sats for 2 character names
  //  42k sats for 3 character names
  //  21k sats for 4 character names
  //  10k sats otherwise

  const { username } = params;
  if (username.length > 32) {
    throw error(400, "Username is too long. Maximum length is 32 characters.");
  }
  if (username.length < 5) {
    throw error(
      400,
      "Username is too short. Minimum length is 5 characters. Shorter usernames are reserved for future use.",
    );
  }

  if (!/^[a-z0-9\-_]+$/.test(username)) {
    throw error(
      400,
      "Invalid username format. Only lowercase letters, numbers, and hyphens are allowed.",
    );
  }

  if (await userExists(username)) {
    throw error(400, "User already exists");
  }

  if (isNpub(username)) {
    throw error(
      400,
      "Username is a valid npub. Please use a username instead.",
    );
  }

  const db = await getDb();

  const body = await request.json();
  const { npub }: {
    npub: `npub1${string}`;
  } = body;

  if (!npub) {
    throw error(400, "Missing npub");
  }

  try {
    const decoded = nip19.decode(npub);
    if (decoded.type !== "npub") {
      throw error(400, "Invalid npub");
    }
  } catch {
    throw error(400, "Invalid npub");
  }

  await db.execute(
    "INSERT INTO users (username, npub) VALUES (?, ?)",
    [username, npub],
  );

  return json({
    success: true,
  });
}

export async function OPTIONS() {
  return new Response(null, {
    headers: {
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
      "Access-Control-Allow-Headers": "Content-Type",
    },
  });
}
