import type { Metadata } from "next";
import { SITE_URL } from "@/config/site";
import {
  DEFAULT_LANGUAGE,
  ENABLED_LANGUAGES,
  getLanguageDefinition,
  type AppLanguage,
} from "./registry";
import {
  getLocaleBundle,
  type SeoPageKey,
  type SeoPageMeta,
  type SeoSiteMeta,
} from "./resources";

export const SITE_BASE_URL = SITE_URL;

type SeoJson = {
  site: SeoSiteMeta;
  pages: Record<string, SeoPageMeta & { keywords?: string[] }>;
  listTemplates: Record<string, Record<string, string | Record<string, string>>>;
};

function getSeoBundle(lang: AppLanguage): SeoJson {
  return getLocaleBundle(lang).seo as SeoJson;
}

export function interpolateTemplate(
  template: string,
  vars: Record<string, string>
): string {
  return template.replace(/\{\{(\w+)\}\}/g, (_, key: string) => vars[key] ?? "");
}

export function getSiteSeoMeta(lang: AppLanguage = DEFAULT_LANGUAGE): SeoSiteMeta {
  return getSeoBundle(lang).site;
}

export function getSeoPage(
  pageKey: SeoPageKey,
  lang: AppLanguage = DEFAULT_LANGUAGE
): SeoPageMeta {
  const bundle = getSeoBundle(lang);
  const page = bundle.pages[pageKey];
  if (!page) {
    throw new Error(`Missing SEO page key: ${String(pageKey)}`);
  }

  return {
    title: page.title,
    description: page.description,
    path: page.path,
    keywords: page.keywords ?? bundle.site.keywords,
    h1: page.h1,
  };
}

export function getListSeoTemplates(lang: AppLanguage = DEFAULT_LANGUAGE) {
  return getSeoBundle(lang).listTemplates;
}

/** Title format: SiteName | core (or core already includes suffix) */
export function formatLocalizedSeoTitle(
  core: string,
  lang: AppLanguage = DEFAULT_LANGUAGE
): string {
  const site = getSiteSeoMeta(lang);
  const trimmed = core.trim();
  if (!trimmed) return site.name;
  if (
    trimmed.startsWith(`${site.name} |`) ||
    trimmed.endsWith(`| ${site.titleSuffix}`) ||
    trimmed.includes(`| ${site.titleSuffix}`)
  ) {
    return trimmed;
  }
  return `${site.titleSuffix} | ${trimmed}`;
}

export function buildLocalizedLocationLabel(
  options: { cityName?: string; provinceName?: string },
  lang: AppLanguage = DEFAULT_LANGUAGE
): string {
  const location = getListSeoTemplates(lang).location as Record<string, string>;
  if (options.cityName) {
    return interpolateTemplate(location.inCity, { city: options.cityName });
  }
  if (options.provinceName) {
    return interpolateTemplate(location.inProvince, {
      province: options.provinceName,
    });
  }
  return "";
}

export function buildHreflangAlternates(path: string) {
  const normalizedPath = path.startsWith("/") ? path : `/${path}`;
  const canonical = `${SITE_URL}${normalizedPath}`;
  const languages: Record<string, string> = {};

  for (const code of ENABLED_LANGUAGES) {
    languages[code] = canonical;
  }
  languages["x-default"] = canonical;

  return { canonical, languages };
}

export function buildLocalizedOpenGraphLocale(lang: AppLanguage): string {
  return getLanguageDefinition(lang).ogLocale;
}

export type LocalizedMetadataInput = {
  title: string;
  description: string;
  path: string;
  lang?: AppLanguage;
  type?: "website" | "article" | "profile";
  publishedTime?: string;
  modifiedTime?: string;
  imageUrl?: string;
  imageAlt?: string;
  keywords?: string[];
  ogTitle?: string;
  appendSiteName?: boolean;
  index?: boolean;
};

/** Builds Next.js Metadata fields that depend on locale (used by generatePageMetadata) */
export function buildLocalizedMetadataFields(
  options: LocalizedMetadataInput
): Pick<
  Metadata,
  "title" | "description" | "keywords" | "alternates" | "robots" | "openGraph"
> {
  const lang = options.lang ?? DEFAULT_LANGUAGE;
  const site = getSiteSeoMeta(lang);
  const ogLocale = buildLocalizedOpenGraphLocale(lang);

  const finalTitle = options.appendSiteName
    ? `${options.title} | ${site.titleSuffix}`
    : options.title;
  const ogTitle = options.ogTitle || finalTitle;
  const finalDescription = options.description || site.defaultDescription;

  return {
    // {absolute} skips the root layout's "%s | siteName" template — finalTitle
    // already carries the site-name suffix, so applying the template again
    // would duplicate it.
    title: { absolute: finalTitle },
    description: finalDescription,
    keywords: options.keywords ?? site.keywords,
    alternates: buildHreflangAlternates(options.path),
    robots: {
      index: options.index !== false,
      follow: true,
    },
    openGraph: {
      title: ogTitle,
      description: finalDescription,
      url: `${SITE_URL}${options.path.startsWith("/") ? options.path : `/${options.path}`}`,
      siteName: site.name,
      locale: ogLocale,
      type: options.type || "website",
    },
  };
}
