import { Router } from "express";

import { asyncHandler } from "../../lib/async-handler.js";
import { requireAuth } from "../../middleware/auth.js";

type ReverseResult = {
  label: string;
  fetchedAt: number;
};

const reverseCache = new Map<string, ReverseResult>();
const CACHE_TTL_MS = 1000 * 60 * 30;

const buildLocationLabel = (address: Record<string, string | undefined>) => {
  const street = address.road
    ?? address.pedestrian
    ?? address.footway
    ?? address.cycleway
    ?? address.path
    ?? address.residential
    ?? address.neighbourhood
    ?? address.suburb
    ?? address.quarter;

  const locality = address.house_number
    ? `${street ?? "Brak ulicy"} ${address.house_number}`
    : street
      ?? address.neighbourhood
      ?? address.suburb
      ?? address.city_district
      ?? address.village
      ?? address.town
      ?? address.city
      ?? "Brak adresu";

  const area = address.suburb
    ?? address.city_district
    ?? address.village
    ?? address.town
    ?? address.city
    ?? address.county;

  if (!area || locality.includes(area)) {
    return locality;
  }

  return `${locality}, ${area}`;
};

export const geocodingRouter = Router();

geocodingRouter.use(requireAuth);

geocodingRouter.get(
  "/reverse",
  asyncHandler(async (request, response) => {
    const lat = Number(request.query.lat);
    const lon = Number(request.query.lon);

    if (!Number.isFinite(lat) || !Number.isFinite(lon)) {
      return response.status(400).json({ message: "Invalid coordinates" });
    }

    const cacheKey = `${lat.toFixed(5)}:${lon.toFixed(5)}`;
    const cached = reverseCache.get(cacheKey);
    if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {
      return response.json({ item: { label: cached.label } });
    }

    const url = new URL("https://nominatim.openstreetmap.org/reverse");
    url.searchParams.set("format", "jsonv2");
    url.searchParams.set("lat", String(lat));
    url.searchParams.set("lon", String(lon));
    url.searchParams.set("zoom", "18");
    url.searchParams.set("addressdetails", "1");

    const reverseResponse = await fetch(url, {
      headers: {
        "User-Agent": "VisauTracker/1.0 (track.visau.duckdns.org)",
        Accept: "application/json",
      },
    });

    if (!reverseResponse.ok) {
      return response.status(502).json({ message: "Reverse geocoding failed" });
    }

    const payload = (await reverseResponse.json()) as {
      display_name?: string;
      address?: Record<string, string | undefined>;
    };

    const label = payload.address ? buildLocationLabel(payload.address) : payload.display_name ?? "Brak adresu";
    reverseCache.set(cacheKey, { label, fetchedAt: Date.now() });

    response.json({ item: { label } });
  }),
);
