import crypto from "node:crypto"

// Helper function to calculate the latitude offset
export function calculateLatWithOffset(
  latitude: number,
  offsetPx: number,
  zoomLevel: number
): number {
  const earthCircumference = 40075017 // Earth's circumference in meters
  const tileSize = 256 // Height of a tile in pixels (standard in Google Maps)

  // Calculate ground resolution (meters per pixel) at the given latitude and zoom level
  const groundResolution =
    (earthCircumference * Math.cos((latitude * Math.PI) / 180)) /
    (tileSize * Math.pow(2, zoomLevel))

  // Calculate the number of meters for the given offset in pixels
  const metersOffset = groundResolution * offsetPx

  // Convert the meters offset into a latitude offset (1 degree latitude is ~111,320 meters)
  const latOffset = metersOffset / 111320

  // Return the new latitude by subtracting the offset
  return latitude - latOffset
}

/**
 * Util functions taken from https://developers.google.com/maps/documentation/maps-static/digital-signature#sample-code-for-url-signing
 * Used to sign the URL for the Google Static Maps API.
 */

/**
 * Convert from 'web safe' base64 to true base64.
 *
 * @param  {string} safeEncodedString The code you want to translate
 *                                    from a web safe form.
 * @return {string}
 */
function removeWebSafe(safeEncodedString: string) {
  return safeEncodedString.replace(/-/g, "+").replace(/_/g, "/")
}

/**
 * Convert from true base64 to 'web safe' base64
 *
 * @param  {string} encodedString The code you want to translate to a
 *                                web safe form.
 * @return {string}
 */
function makeWebSafe(encodedString: string) {
  return encodedString.replace(/\+/g, "-").replace(/\//g, "_")
}

/**
 * Takes a base64 code and decodes it.
 *
 * @param  {string} code The encoded data.
 * @return {string}
 */
function decodeBase64Hash(code: string) {
  return Buffer.from(code, "base64")
}

/**
 * Takes a key and signs the data with it.
 *
 * @param  {string} key  Your unique secret key.
 * @param  {string} data The url to sign.
 * @return {string}
 */
function encodeBase64Hash(key: Buffer, data: string) {
  return crypto.createHmac("sha1", key).update(data).digest("base64")
}

/**
 * Sign a URL using a secret key.
 *
 * @param  {URL} url   The url you want to sign.
 * @param  {string} secret Your unique secret key.
 * @return {string}
 */
export function getUrlWithSignature(url: URL, secret = "") {
  const path = url.pathname + url.search
  const safeSecret = decodeBase64Hash(removeWebSafe(secret))
  const hashedSignature = makeWebSafe(encodeBase64Hash(safeSecret, path))

  return `${url.toString()}&signature=${hashedSignature}`
}
