import type { Metadata } from "next";

import { routing } from "../i18n/routing";
import {
  PAGE_TITLE_TOKEN,
  SITE_NAME_TOKEN,
  type SiteSettings,
  type SiteSettingsMediaBindings,
} from "./site-settings";
import {
  getSiteSettings,
  getSiteSettingsMediaBindings,
} from "./app-config";
import { AppLocale, getLocalizedPath, resolveLocale } from "./locale";
import { buildSiteIconUrls } from "./site-icons";

function getSiteUrl(): URL {
  return new URL(process.env.NEXT_PUBLIC_SITE_URL ?? "https://mohfarawati.de");
}

function toAbsoluteUrl(pathname: string): string {
  return new URL(pathname, getSiteUrl()).toString();
}

export function buildLocaleAlternates(pathname: string) {
  const languages = Object.fromEntries(
    routing.locales.map((locale) => [locale, toAbsoluteUrl(getLocalizedPath(locale, pathname))]),
  ) as Record<AppLocale, string>;

  return {
    canonical: toAbsoluteUrl(getLocalizedPath(routing.defaultLocale, pathname)),
    languages: {
      ...languages,
      "x-default": toAbsoluteUrl(getLocalizedPath(routing.defaultLocale, pathname)),
    },
  };
}

export function applyTitleTemplateFn(title: string, template: string, siteName: string): string {
  const safeTemplate = template.includes(PAGE_TITLE_TOKEN)
    ? template
    : `${PAGE_TITLE_TOKEN} | ${SITE_NAME_TOKEN}`;

  return safeTemplate
    .replaceAll(SITE_NAME_TOKEN, siteName)
    .replace(PAGE_TITLE_TOKEN, title);
}

function buildMetadataImages(imageUrl?: string | null) {
  if (!imageUrl) {
    return undefined;
  }

  return [
    {
      url: toAbsoluteUrl(imageUrl),
    },
  ];
}

export async function buildAppMetadata(): Promise<Metadata> {
  const [settings, bindings] = await Promise.all([getSiteSettings(), getSiteSettingsMediaBindings()]);

  return buildAppMetadataFromConfig(settings, bindings);
}

export function buildAppMetadataFromConfig(
  settings: SiteSettings,
  bindings: SiteSettingsMediaBindings,
): Metadata {
  const defaultLocaleSettings = settings.locales[routing.defaultLocale];
  const openGraphImages = buildMetadataImages(bindings.defaultOgImage?.url);
  const siteIconUrls = buildSiteIconUrls({
    siteName: defaultLocaleSettings.siteName,
    faviconVersion: bindings.favicon?.version,
    faviconUrl: bindings.favicon?.url,
  });

  return {
    metadataBase: getSiteUrl(),
    title: defaultLocaleSettings.siteName,
    description: defaultLocaleSettings.siteDescription,
    applicationName: defaultLocaleSettings.siteName,
    manifest: siteIconUrls.manifestHref,
    icons: {
      icon: [{ url: siteIconUrls.faviconHref }],
      shortcut: [{ url: siteIconUrls.faviconHref }],
      apple: [{ url: siteIconUrls.appleIconHref }],
    },
    openGraph: {
      title: defaultLocaleSettings.siteName,
      description: defaultLocaleSettings.siteDescription,
      url: toAbsoluteUrl(getLocalizedPath(routing.defaultLocale, "/")),
      siteName: defaultLocaleSettings.siteName,
      locale: routing.defaultLocale,
      type: "website",
      images: openGraphImages,
    },
    twitter: {
      card: openGraphImages ? "summary_large_image" : "summary",
      title: defaultLocaleSettings.siteName,
      description: defaultLocaleSettings.siteDescription,
      images: openGraphImages?.map((image) => image.url),
    },
  };
}

type LocalizedMetadataInput = {
  locale: string;
  pathname: string;
  title: string;
  description?: string;
  applyTitleTemplate?: boolean;
};

export async function buildLocalizedMetadata({
  locale,
  pathname,
  title,
  description,
  applyTitleTemplate,
}: LocalizedMetadataInput): Promise<Metadata> {
  const localeKey = resolveLocale(locale);
  const [settings, bindings] = await Promise.all([getSiteSettings(), getSiteSettingsMediaBindings()]);

  return buildLocalizedMetadataFromConfig({
    settings,
    bindings,
    locale: localeKey,
    pathname,
    title,
    description,
    applyTitleTemplate,
  });
}

export function buildLocalizedMetadataFromConfig(input: {
  settings: SiteSettings;
  bindings: SiteSettingsMediaBindings;
  locale: AppLocale;
  pathname: string;
  title: string;
  description?: string;
  applyTitleTemplate?: boolean;
}): Metadata {
  const {
    settings,
    bindings,
    locale,
    pathname,
    title,
    description,
    applyTitleTemplate = true,
  } = input;
  const localeKey = resolveLocale(locale);
  const localeSettings = settings.locales[localeKey];
  const resolvedDescription = description?.trim() || localeSettings.siteDescription;
  const resolvedTitle = applyTitleTemplate
    ? applyTitleTemplateFn(title, localeSettings.titleTemplate, localeSettings.siteName)
    : title;
  const openGraphImages = buildMetadataImages(bindings.defaultOgImage?.url);

  return {
    title: resolvedTitle,
    description: resolvedDescription,
    alternates: buildLocaleAlternates(pathname),
    openGraph: {
      title: resolvedTitle,
      description: resolvedDescription,
      url: toAbsoluteUrl(getLocalizedPath(localeKey, pathname)),
      siteName: localeSettings.siteName,
      locale: localeKey,
      type: "website",
      images: openGraphImages,
    },
    twitter: {
      card: openGraphImages ? "summary_large_image" : "summary",
      title: resolvedTitle,
      description: resolvedDescription,
      images: openGraphImages?.map((image) => image.url),
    },
  };
}
