import "server-only";
import { cache } from "react";
import { z } from "zod";
import { site } from "@/content/site";

export type ReviewSummary = {
  rating: number;
  count: number;
  checkedOn: string;
  source: "google-places" | "snapshot";
};

const PLACES_ENDPOINT = "https://places.googleapis.com/v1/places/";
const FIELD_MASK = "rating,userRatingCount";
const REQUEST_TIMEOUT_MS = 5000;
const placeSchema = z.object({
  rating: z.number().min(0).max(5),
  userRatingCount: z.number().int().nonnegative(),
});

export const snapshotSummary = (): ReviewSummary => ({
  ...site.reviews.snapshot,
  source: "snapshot",
});

export function parsePlaceSummary(
  payload: unknown,
  checkedOn: string,
): ReviewSummary {
  const place = placeSchema.parse(payload);
  return {
    rating: place.rating,
    count: place.userRatingCount,
    checkedOn,
    source: "google-places",
  };
}

type FetchInput = {
  key: string | undefined;
  placeId: string;
  fetch?: typeof globalThis.fetch;
  now?: () => Date;
};
export async function fetchReviewSummary({
  key,
  placeId,
  fetch = globalThis.fetch,
  now = () => new Date(),
}: FetchInput): Promise<ReviewSummary> {
  const apiKey = key?.trim();
  if (!apiKey) return snapshotSummary();
  try {
    const response = await fetch(
      `${PLACES_ENDPOINT}${encodeURIComponent(placeId)}`,
      {
        headers: { "X-Goog-Api-Key": apiKey, "X-Goog-FieldMask": FIELD_MASK },
        signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
      },
    );
    if (!response.ok)
      throw new Error(`Google Places responded ${response.status}`);
    return parsePlaceSummary(
      await response.json(),
      now().toISOString().slice(0, 10),
    );
  } catch (error) {
    console.warn(
      `Google reviews badge: showing the ${site.reviews.snapshot.checkedOn} snapshot because the live figures were unavailable (${error instanceof Error ? error.message : "unknown error"}).`,
    );
    return snapshotSummary();
  }
}

export const getReviewSummary = cache(() =>
  fetchReviewSummary({
    key: process.env.GOOGLE_PLACES_API_KEY,
    placeId: site.reviews.placeId,
  }),
);

export const reviewNoun = (count: number) =>
  count === 1 ? "review" : "reviews";
export const formatCheckedOn = (checkedOn: string) =>
  new Intl.DateTimeFormat("en-SG", {
    day: "numeric",
    month: "long",
    year: "numeric",
    timeZone: "UTC",
  }).format(new Date(`${checkedOn}T00:00:00Z`));

export const describeRating = ({ rating, count, checkedOn }: ReviewSummary) =>
  `Rated ${rating.toFixed(1)} out of 5 from ${count} Google ${reviewNoun(count)} as at ${formatCheckedOn(checkedOn)}`;
