import Redis from "ioredis";
import type { NextApiRequest, NextApiResponse } from "next";
import { env } from "~/env";

let tiles: Redis | null = null;

export function getTilesClient() {
	if (env.SKIP_REDIS === "true") {
		return null;
	}
	if (!tiles) {
		tiles = new Redis(`keydb://${env.TILES_URL}`);
	}
	return tiles;
}
/*
 * /api/tiles/[[...slug]]
 * This API route is used to fetch tiles from OpenStreetMap and cache them in KeyDb.
 * The tile URL is constructed using the provided slug parameters: /api/tiles/s/z/x/y
 * The slug should be an array of 4 elements: [s, z, x, y].
 * The API caches the tile for 30 days and sets appropriate headers for caching.
 */
export default async function handler(
	req: NextApiRequest,
	res: NextApiResponse,
) {
	const { slug } = req.query;

	if (!slug) {
		return res.status(400).json({
			error: "Slug is required",
		});
	}
	if (!Array.isArray(slug) || slug.length !== 4) {
		return res.status(400).json({
			error: "Slug must be an array of 4 elements",
		});
	}
	const s = slug[0];
	const z = slug[1];
	const x = slug[2];
	const y = slug[3];
	if (
		!s ||
		Number.isNaN(Number(z)) ||
		Number.isNaN(Number(x)) ||
		Number.isNaN(Number(y))
	) {
		return res.status(400).json({
			error: "Invalid slug format",
		});
	}

	const cacheKey = `tile:${z}:${x}:${y}`;

	const tiles = getTilesClient();
	if (!tiles) {
		return res.status(500).json({
			error: "KeyDB client is not initialized",
		});
	}

	const cachedTile = await tiles.getBuffer(cacheKey);
	if (cachedTile) {
		res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
		res.setHeader("Content-Type", "image/png");
		res.setHeader("Content-Length", cachedTile.length);

		return res.status(200).send(cachedTile);
	}

	const osmUrl = `https://${s}.tile.openstreetmap.org/${z}/${x}/${y}.png`;

	try {
		const response = await fetch(osmUrl);
		if (!response.ok) {
			return res.status(response.status).json({
				error: `Failed to fetch tile from OSM: ${response.statusText}`,
			});
		}
		const tileData = await response.arrayBuffer();
		const data = Buffer.from(tileData);
		// Cache for 30 days
		await tiles.setex(cacheKey, 2592000, data);

		res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
		res.setHeader("Content-Type", "image/png");
		res.setHeader("Content-Length", data.length);

		return res.status(200).send(data);
	} catch (e) {
		return res.status(500).json({
			error: `Failed to fetch tile from OSM: ${(e as Error).message}`,
		});
	}
}
