import type { Metadata } from "next";
import { notFound } from "next/navigation";
import { cache } from "react";
import PlaceExplorer from "@/app/sted/[slug]/PlaceExplorer";
import {
  buildPlaceAverageComparison,
  buildPlaceStats,
  buildPlaceStatsIntro,
  formatPlaceCount,
  formatPlaceCurrency,
  type FacilityRecord,
  enrichFacilities,
  filterFacilitiesByArea,
  getPlaceConfigFromSlug,
  getPlacePreposition,
} from "@/app/facilityData";
import { API_URL } from "@/config/constants";
import {
  createBreadcrumbJsonLd,
  createCollectionPageJsonLd,
  createItemListJsonLd,
  createPageMetadata,
  resolveSeoDescription,
  resolveSeoTitle,
} from "@/app/seo";
import { fetchPublicFacilities } from "@/app/publicFacilities";

type PlacePageData = {
  slug?: string;
  factbox_intro_html?: string | null;
  meta_title?: string | null;
  meta_description?: string | null;
  updated_at?: string | null;
};

const escapeHtml = (value: string) =>
  value
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#39;");

const sanitizeHref = (value: string) => {
  const href = value.trim();
  return /^(https?:|mailto:|tel:|\/|#)/i.test(href) ? href : "#";
};

const isInternalTeeoffHref = (href: string) =>
  /^(\/|#|mailto:|tel:)/i.test(href) || /^https?:\/\/([^/]+\.)?teeoff\.no(\/|$)/i.test(href);

const sanitizePlaceRichText = (value: string | null | undefined) => {
  const source = String(value || "").replace(/\r\n?/g, "\n");
  if (!source.trim()) return "";

  const placeholders = new Map<string, string>();
  let index = 0;
  const keep = (html: string) => {
    const key = `__HTML_TOKEN_${index++}__`;
    placeholders.set(key, html);
    return key;
  };

  let safe = source
    .replace(/<\s*br\s*\/?\s*>/gi, () => keep("<br />"))
    .replace(/<\s*(strong|b)\s*>/gi, () => keep("<strong>"))
    .replace(/<\s*\/\s*(strong|b)\s*>/gi, () => keep("</strong>"))
    .replace(/<\s*(em|i)\s*>/gi, () => keep("<em>"))
    .replace(/<\s*\/\s*(em|i)\s*>/gi, () => keep("</em>"))
    .replace(/<\s*u\s*>/gi, () => keep("<u>"))
    .replace(/<\s*\/\s*u\s*>/gi, () => keep("</u>"))
    .replace(/<\s*(p|blockquote)\s*>/gi, (_, tag: string) => keep(`<${tag.toLowerCase()}>`))
    .replace(/<\s*\/\s*(p|blockquote)\s*>/gi, (_, tag: string) => keep(`</${tag.toLowerCase()}>`))
    .replace(/<\s*(ul|ol)\s*>/gi, (_, tag: string) => keep(`<${tag.toLowerCase()}>`))
    .replace(/<\s*\/\s*(ul|ol)\s*>/gi, (_, tag: string) => keep(`</${tag.toLowerCase()}>`))
    .replace(/<\s*li\s*>/gi, () => keep("<li>"))
    .replace(/<\s*\/\s*li\s*>/gi, () => keep("</li>"))
    .replace(/<\s*(h2|h3)\s*>/gi, (_, tag: string) => keep(`<${tag.toLowerCase()}>`))
    .replace(/<\s*\/\s*(h2|h3)\s*>/gi, (_, tag: string) => keep(`</${tag.toLowerCase()}>`))
    .replace(/<\s*a\b([^>]*)>/gi, (_, attrs: string) => {
      const hrefMatch = attrs.match(/href\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i);
      const href = sanitizeHref(hrefMatch?.[1] || hrefMatch?.[2] || hrefMatch?.[3] || "#");
      if (isInternalTeeoffHref(href)) {
        return keep(`<a href="${escapeHtml(href)}">`);
      }
      return keep(`<a href="${escapeHtml(href)}" target="_blank" rel="noreferrer noopener">`);
    })
    .replace(/<\s*\/\s*a\s*>/gi, () => keep("</a>"));

  safe = escapeHtml(safe).replace(/\n/g, "<br />");

  for (const [token, html] of placeholders) {
    safe = safe.replaceAll(token, html);
  }

  return safe;
};

export const dynamicParams = true;
export const revalidate = 3600;

const fetchPlacePageData = cache(async (slug: string): Promise<PlacePageData | null> => {
  try {
    const res = await fetch(`${API_URL}/place-pages/${slug}`, {
      cache: "no-store",
    });

    if (!res.ok) {
      return null;
    }

    return (await res.json()) as PlacePageData;
  } catch {
    return null;
  }
});

export async function generateMetadata({
  params,
}: {
  params: Promise<{ slug: string }>;
}): Promise<Metadata> {
  const { slug } = await params;
  const place = getPlaceConfigFromSlug(slug);

  if (!place) {
    return createPageMetadata({
      title: "Sted ikke funnet",
      description: "Denne stedssiden finnes ikke på TeeOff.",
      path: `/sted/${slug}`,
    });
  }

  const placePage = await fetchPlacePageData(slug);
  const fallbackDescription = `${place.intro} TeeOff samler golfbaner i ${place.label} med oppdatert banestatus og baneprofiler.`;

  return createPageMetadata({
    title: resolveSeoTitle(placePage?.meta_title, place.title),
    description: resolveSeoDescription(placePage?.meta_description, fallbackDescription),
    path: `/sted/${slug}`,
  });
}

export default async function PlacePage({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  const place = getPlaceConfigFromSlug(slug);

  if (!place) {
    notFound();
  }

  let placePage: PlacePageData | null = null;

  const facilities = await fetchPublicFacilities<FacilityRecord>("place", revalidate);

  try {
    placePage = await fetchPlacePageData(slug);
    if (!placePage) {
      throw new Error("API returnerte ingen sted-side.");
    }
  } catch (error) {
    console.error("Kritisk feil ved henting av sted-sideinnhold:", error);
    placePage = null;
  }

  const safeData = Array.isArray(facilities) ? facilities : [];
  const enrichedFacilities = enrichFacilities(safeData);
  const facilitiesInPlace = filterFacilitiesByArea(enrichedFacilities, place.areaFilter);
  const placeStats = buildPlaceStats(facilitiesInPlace);
  const nationalStats = buildPlaceStats(enrichedFacilities);
  const placeStatsIntro = buildPlaceStatsIntro(place.label, placeStats);
  const isNationalPlace = place.slug === "norge";
  const placePreposition = isNationalPlace ? "i" : getPlacePreposition(place.label);
  const greenfeeComparison = isNationalPlace
    ? null
    : buildPlaceAverageComparison(placeStats.avgPrimetimeGreenfee, nationalStats.avgPrimetimeGreenfee);
  const membershipComparison = isNationalPlace
    ? null
    : buildPlaceAverageComparison(placeStats.avgStandardMembership, nationalStats.avgStandardMembership);
  const holeDistributionParts = [
    `${formatPlaceCount(placeStats.par3HoleCount)} par 3-hull`,
    `${formatPlaceCount(placeStats.par4HoleCount)} par 4-hull`,
    `${formatPlaceCount(placeStats.par5HoleCount)} par 5-hull`,
    placeStats.par6HoleCount > 0 ? `${formatPlaceCount(placeStats.par6HoleCount)} par 6-hull` : null,
  ].filter((part): part is string => Boolean(part));
  const holeDistributionText =
    holeDistributionParts.length > 1
      ? `${holeDistributionParts.slice(0, -1).join(", ")} og ${holeDistributionParts.at(-1)}`
      : holeDistributionParts[0] ?? null;
  const shortestLongestText =
    placeStats.shortestHoleMeters !== null && placeStats.longestHoleMeters !== null
      ? `Det korteste golfhullet ${placePreposition} ${place.label} er ${placeStats.shortestHoleMeters} meter, mens det lengste er ${placeStats.longestHoleMeters} meter.`
      : null;
  const collectionJsonLd = createCollectionPageJsonLd({
    name: resolveSeoTitle(placePage?.meta_title, place.title),
    description: resolveSeoDescription(
      placePage?.meta_description,
      `${place.intro} TeeOff samler golfbaner i ${place.label} med oppdatert banestatus og baneprofiler.`,
    ),
    path: `/sted/${slug}`,
  });
  const itemListJsonLd = createItemListJsonLd({
    name: resolveSeoTitle(placePage?.meta_title, place.title),
    path: `/sted/${slug}`,
    items: facilitiesInPlace
      .filter((facility) => facility?.slug && facility?.name)
      .map((facility) => ({
        name: facility.name,
        path: `/golfbaner/${facility.slug}`,
        description: facility.description,
      })),
  });
  const breadcrumbJsonLd = createBreadcrumbJsonLd([
    { name: "Hjem", path: "/" },
    { name: "Steder", path: "/sted/norge" },
    { name: place.label, path: `/sted/${slug}` },
  ]);

  return (
    <>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(collectionJsonLd) }}
      />
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(itemListJsonLd) }}
      />
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumbJsonLd) }}
      />
      <main className="site-shell min-h-screen">
        <section className="mx-auto max-w-[1400px] px-4 py-8 sm:px-6 sm:py-10 lg:px-8 lg:py-12">
          <div className="max-w-4xl">
            <p className="mb-3 text-[11px] font-extrabold uppercase tracking-[0.3em] text-[#6FA786]">Steder</p>
            <h1 className="section-title text-4xl text-[#112015] sm:text-5xl lg:text-6xl">{place.title}</h1>
            <p className="mt-4 max-w-3xl text-base leading-8 text-[#617063]">{place.intro}</p>
            <div className="mt-5 flex flex-wrap gap-3">
              <span className="rounded-full bg-white px-4 py-2 text-[11px] font-extrabold uppercase tracking-[0.18em] text-[#112015] shadow-sm">
                {placeStats.facilityCount} golfanlegg
              </span>
            </div>
          </div>

          {placePage?.factbox_intro_html ? (
            <section className="mt-8 overflow-hidden rounded-[2rem] border border-[#E7D8CE] bg-[#fff8f4] shadow-sm">
              <div className="px-5 py-6 sm:px-6 lg:px-8 lg:py-8">
                <div
                  className="max-w-4xl text-base leading-8 text-[#4e3d34] [&_a]:font-bold [&_a]:text-[#d53300] [&_a]:underline [&_a]:underline-offset-2 hover:[&_a]:text-[#a82800] [&_blockquote]:border-l-4 [&_blockquote]:border-[#e4b9a8] [&_blockquote]:pl-4 [&_em]:italic [&_h2]:mt-8 [&_h2]:text-2xl [&_h2]:font-black [&_h2]:text-[#112015] [&_h2:first-child]:mt-0 [&_h3]:mt-6 [&_h3]:text-xl [&_h3]:font-black [&_h3]:text-[#112015] [&_ol]:my-5 [&_ol]:list-decimal [&_ol]:pl-6 [&_p]:mb-5 [&_p:last-child]:mb-0 [&_strong]:font-bold [&_u]:underline [&_ul]:my-5 [&_ul]:list-disc [&_ul]:pl-6"
                  dangerouslySetInnerHTML={{ __html: sanitizePlaceRichText(placePage.factbox_intro_html) }}
                />
              </div>
            </section>
          ) : null}

          <section className="mt-8 overflow-hidden rounded-[2rem] border border-[#D7DED0] bg-white shadow-sm">
            <div className="px-5 py-6 sm:px-6 lg:px-8 lg:py-8">
              <div className="max-w-5xl">
                <p className="text-[11px] font-extrabold uppercase tracking-[0.28em] text-[#6FA786]">Nøkkeltall</p>
                <h2 className="mt-2 text-3xl text-[#112015] sm:text-4xl">
                  {isNationalPlace ? "Fakta om golfanleggene i Norge" : `Fakta om golfanleggene ${placePreposition} ${place.label}`}
                </h2>
                <p className="mt-4 text-base leading-8 text-[#213127]">{placeStatsIntro}</p>
              </div>
            </div>

            <div className="grid gap-px border-t border-[#D7DED0] bg-[#D7DED0] lg:grid-cols-3">
              <div className="bg-white/88 px-5 py-5 sm:px-6 lg:px-8">
                <p className="text-[11px] font-extrabold uppercase tracking-[0.2em] text-[#6FA786]">Greenfee</p>
                <p className="mt-2 text-2xl font-black text-[#112015]">
                  {placeStats.avgPrimetimeGreenfee !== null ? formatPlaceCurrency(placeStats.avgPrimetimeGreenfee) : "Mangler grunnlag"}
                </p>
                <p className="mt-2 text-sm leading-6 text-[#4F6052]">
                  {placeStats.avgPrimetimeGreenfee !== null
                    ? "Gjennomsnittlig primetime-pris i høysesong."
                    : "Ingen tilstrekkelige greenfee-data tilgjengelig."}
                </p>
                {greenfeeComparison ? <p className="mt-2 text-sm font-bold text-[#112015]">{greenfeeComparison}</p> : null}
              </div>

              <div className="bg-white/88 px-5 py-5 sm:px-6 lg:px-8">
                <p className="text-[11px] font-extrabold uppercase tracking-[0.2em] text-[#6FA786]">Medlemskap</p>
                <p className="mt-2 text-2xl font-black text-[#112015]">
                  {placeStats.avgStandardMembership !== null ? formatPlaceCurrency(placeStats.avgStandardMembership) : "Mangler grunnlag"}
                </p>
                <p className="mt-2 text-sm leading-6 text-[#4F6052]">
                  {placeStats.avgStandardMembership !== null
                    ? "Gjennomsnittlig standard medlemskap med spillerett."
                    : "Ingen tilstrekkelige medlemskapsdata tilgjengelig."}
                </p>
                {membershipComparison ? <p className="mt-2 text-sm font-bold text-[#112015]">{membershipComparison}</p> : null}
              </div>

              <div className="bg-white/88 px-5 py-5 sm:px-6 lg:px-8">
                <p className="text-[11px] font-extrabold uppercase tracking-[0.2em] text-[#6FA786]">Hullstatistikk</p>
                <p className="mt-2 text-sm leading-7 text-[#112015]">
                  {formatPlaceCount(placeStats.hole18Count, "neuter")} 18-hullsanlegg
                  <br />
                  {formatPlaceCount(placeStats.hole9Count, "neuter")} 9-hullsanlegg
                  <br />
                  {formatPlaceCount(placeStats.hole6Count, "neuter")} 6-hullsanlegg
                  <br />
                  {formatPlaceCount(placeStats.hole27PlusCount, "neuter")} anlegg med 27 hull eller mer
                </p>
                {holeDistributionText ? <p className="mt-3 text-sm leading-6 text-[#4F6052]">{holeDistributionText}.</p> : null}
                {shortestLongestText ? <p className="mt-2 text-sm leading-6 text-[#4F6052]">{shortestLongestText}</p> : null}
              </div>
            </div>
          </section>

          <PlaceExplorer
            facilities={facilitiesInPlace}
            placeLabel={place.label}
            placeAreaFilter={place.areaFilter}
            placeTitle={place.title}
          />
        </section>
      </main>
    </>
  );
}
