"use client"

import { useTranslations, useLocale } from "next-intl"
import Image from "next/image"
import { ExternalLink, ArrowLeft, ArrowRight, Search, X } from "lucide-react"
import type { SocialAction } from "@/lib/actualites-data"
import { useMemo, useEffect, useRef } from "react"
import { motion, AnimatePresence } from "framer-motion"
import SarLoader from "./sar-loader"
import SectionLabel from "@/components/section-label"
import { useCookieConsent } from "./cookie-consent"
import CookieIframePlaceholder from "./cookie-iframe-placeholder"
import BoutonSyncLinkedIn from "./medias/bouton-sync-linkedin"
import BoutonImageActualite from "./medias/bouton-image-actualite"
import BoutonActivationActualite from "./medias/bouton-activation-actualite"
import { useEstConnecte } from "@/lib/session-admin"

const API_URL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000"

function highlight(text: string, query: string): React.ReactNode {
  if (!query.trim()) return text
  const escaped = query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
  const parts = text.split(new RegExp(`(${escaped})`, "gi"))
  return (
    <>
      {parts.map((part, i) =>
        i % 2 === 1
          ? <mark key={i} className="bg-yellow-200 text-inherit not-italic px-0.5 rounded-sm">{part}</mark>
          : part
      )}
    </>
  )
}

function getLinkedInEmbedUrl(postUrl: string): string {
  if (postUrl.includes("urn:li:")) {
    const urnMatch = postUrl.match(/urn:li:(ugcPost|activity|share):(\d+)/)
    if (urnMatch) return `https://www.linkedin.com/embed/feed/update/urn:li:${urnMatch[1]}:${urnMatch[2]}`
  }
  const match = postUrl.match(/activity[-:](\d+)/)
  if (match) return `https://www.linkedin.com/embed/feed/update/urn:li:activity:${match[1]}`
  const m2 = postUrl.match(/ugcPost[-:](\d+)/)
  if (m2) return `https://www.linkedin.com/embed/feed/update/urn:li:ugcPost:${m2[1]}`
  const m3 = postUrl.match(/share[-:](\d+)/)
  if (m3) return `https://www.linkedin.com/embed/feed/update/urn:li:share:${m3[1]}`
  return postUrl
}

export interface ActualitePageLayoutProps {
  /** La tranche déjà révélée, dans l'ordre du flux. */
  actions: SocialAction[]
  allActions?: SocialAction[]
  totalCount?: number
  loading?: boolean
  /** Reste-t-il des publications à révéler sous celles qui sont affichées ? */
  hasMore?: boolean
  /** Appelé quand le bas de la grille approche, puis au clic sur le bouton. */
  onLoadMore?: () => void
  /** Rechargement du flux après une synchronisation LinkedIn. */
  onSynced?: () => void
  /** Une illustration vient d'être posée : seule cette fiche est à rafraîchir. */
  onImageChange?: (id: string, imageUrl: string) => void
  /** Une fiche vient d'être retirée du site ou remise en ligne. */
  onActivationChange?: (id: string, estActive: boolean) => void
  search?: string
  onSearchChange?: (value: string) => void
  modalLinkedInUrl: string | null
  onCloseModal: () => void
  onOpenLinkedIn?: (url: string) => void
}

export default function ActualitePageLayout({
  actions,
  allActions,
  totalCount,
  loading = false,
  hasMore = false,
  onLoadMore,
  onSynced,
  onImageChange,
  onActivationChange,
  search = "",
  onSearchChange,
  modalLinkedInUrl,
  onCloseModal,
  onOpenLinkedIn,
}: ActualitePageLayoutProps) {
  const t = useTranslations("actualite")
  const tCommon = useTranslations("common")
  const locale = useLocale()
  const isEn = locale === "en"
  const { consent } = useCookieConsent()
  // Une seule lecture de session pour toute la grille, plutôt qu'une par fiche.
  const connecte = useEstConnecte()

  const linkedInActions = useMemo(() => (allActions ?? actions).filter(a => a.linkedInUrl), [allActions, actions])
  const modalIndex = modalLinkedInUrl ? linkedInActions.findIndex(a => a.linkedInUrl === modalLinkedInUrl) : -1
  const currentAction = modalIndex >= 0 ? linkedInActions[modalIndex] : null

  const modalPrev = () => {
    if (modalIndex < 0) return
    const prev = linkedInActions[(modalIndex - 1 + linkedInActions.length) % linkedInActions.length]
    onOpenLinkedIn?.(prev.linkedInUrl!)
  }
  const modalNext = () => {
    if (modalIndex < 0) return
    const next = linkedInActions[(modalIndex + 1) % linkedInActions.length]
    onOpenLinkedIn?.(next.linkedInUrl!)
  }

  useEffect(() => {
    const onKey = (e: KeyboardEvent) => {
      if (e.key === "Escape") onCloseModal()
      if (e.key === "ArrowLeft" && modalLinkedInUrl) modalPrev()
      if (e.key === "ArrowRight" && modalLinkedInUrl) modalNext()
    }
    document.addEventListener("keydown", onKey)
    return () => document.removeEventListener("keydown", onKey)
  }, [modalLinkedInUrl, modalIndex])

  useEffect(() => {
    const open = !!modalLinkedInUrl
    document.body.style.overflow = open ? "hidden" : ""
    document.body.classList.toggle("modal-open", open)
    return () => { document.body.style.overflow = ""; document.body.classList.remove("modal-open") }
  }, [modalLinkedInUrl])

  // ── Défilement continu ────────────────────────────────────────────────────
  // Une sentinelle placée sous la grille demande la tranche suivante dès
  // qu'elle approche de l'écran. La marge de 800 px la déclenche avant qu'elle
  // ne soit visible : la suite est déjà posée quand on arrive au bas, et le
  // défilement ne marque jamais d'arrêt.
  const sentinelle = useRef<HTMLDivElement>(null)
  useEffect(() => {
    const el = sentinelle.current
    if (!el || !hasMore || !onLoadMore || loading) return
    const io = new IntersectionObserver(
      (entrees) => { if (entrees.some((e) => e.isIntersecting)) onLoadMore() },
      { rootMargin: "800px 0px" }
    )
    io.observe(el)
    return () => io.disconnect()
  }, [hasMore, onLoadMore, loading, actions.length])

  const nombre = totalCount ?? actions.length
  const decompte = search.trim()
    ? t("resultsCount", { count: nombre })
    : isEn
      ? `${nombre} publications`
      : `${nombre} publication${nombre > 1 ? "s" : ""}`

  return (
    <>
      <section className="bg-white pb-16 pt-8">

        <div className="mx-auto mb-6 max-w-[98%] px-3 sm:px-4 lg:px-6">
          <SectionLabel title={t("sectionLabel")} size="small" variant="overline" />
        </div>

        <div className="mx-auto w-full max-w-7xl px-4 sm:px-6 lg:px-8">

          {/* ── Barre d'outils : ce qu'il y a, et de quoi le chercher ──────
              La recherche etait deja cablee cote donnees mais n'avait jamais
              de champ a l'ecran. Sur deux cent soixante-huit publications,
              c'est le seul moyen de retrouver une annonce precise. */}
          <div className="flex flex-col gap-4 border-b border-neutral-200 pb-5 sm:flex-row sm:items-center sm:justify-between">
            <p className="text-[11px] font-semibold uppercase tracking-widest text-gray-400">
              {decompte}
            </p>

            <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:gap-3">
            {/* Ne s'affiche que pour un utilisateur connecte : le visiteur ne
                voit qu'un decompte et un champ de recherche. */}
            <BoutonSyncLinkedIn onSynced={onSynced} />

            {onSearchChange && (
              <div className="relative w-full sm:w-80">
                <Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400" aria-hidden />
                <input
                  type="search"
                  value={search}
                  onChange={(e) => onSearchChange(e.target.value)}
                  placeholder={t("searchPlaceholder")}
                  aria-label={t("searchPlaceholder")}
                  className="w-full border border-neutral-200 bg-white py-2.5 pl-9 pr-9 text-[13px] text-gray-900 transition-colors placeholder:text-gray-400 focus:border-primary focus:outline-none [&::-webkit-search-cancel-button]:hidden"
                />
                {search && (
                  <button
                    type="button"
                    onClick={() => onSearchChange("")}
                    aria-label={isEn ? "Clear search" : "Effacer la recherche"}
                    className="absolute right-2 top-1/2 inline-flex h-7 w-7 -translate-y-1/2 items-center justify-center text-gray-400 transition-colors hover:text-primary"
                  >
                    <X className="h-4 w-4" />
                  </button>
                )}
              </div>
            )}
            </div>
          </div>

          <div id="actualite-liste" className="scroll-mt-32">

            {loading && <SarLoader />}

            {!loading && actions.length === 0 && (
              <div className="mx-auto mt-10 max-w-md border-2 border-gray-200 bg-white p-6 shadow-sm">
                <p className="text-sm font-bold text-gray-900">
                  {search.trim() ? t("noResults", { query: search }) : t("noNews")}
                </p>
                <div className="my-3 h-0.5 w-10 rounded-full bg-primary/70" aria-hidden />
                <p className="text-sm leading-relaxed text-gray-500">
                  {search.trim()
                    ? (isEn ? "Try another wording." : "Essayez une autre formulation.")
                    : (isEn ? "Please check back later." : "Revenez consulter cette page régulièrement.")}
                </p>
              </div>
            )}

            {/* ── La grille ────────────────────────────────────────────────
                Meme gabarit de carte que les actualites de l'accueil : filet
                de 2 px, image separee par un filet de meme epaisseur, legere
                elevation au survol. Trois colonnes au plus : au-dela, le titre
                se replierait sur cinq lignes. */}
            {!loading && actions.length > 0 && (
              <div className="mt-8 grid grid-cols-1 gap-5 sm:grid-cols-2 sm:gap-6 lg:grid-cols-3">
                {actions.map((action) => {
                  // L'API n'expose l'état qu'aux administrateurs ; pour tout
                  // le monde, une fiche servie est une fiche publiée.
                  const estActive = action.estActive !== false
                  const titre = (isEn ? action.titleEn : action.title) || ""
                  const texte = (isEn ? action.descriptionEn : action.description) || ""
                  const extrait = texte.replace(/\n+/g, " ").trim()
                  // L'image n'est plus remplacee par une vignette generique :
                  // une meme illustration repetee sur un cinquieme des cartes
                  // faisait un mur de doublons. Sans photographie, la carte
                  // donne davantage de texte a lire.
                  let imageUrl = action.image || ""
                  if (imageUrl && !imageUrl.startsWith("http") && !imageUrl.startsWith("/")) {
                    imageUrl = `${API_URL}/${imageUrl}`
                  }
                  const dateLabel = action.date
                    ? new Date(action.date).toLocaleDateString(
                        isEn ? "en-GB" : "fr-FR",
                        { day: "numeric", month: "long", year: "numeric" }
                      )
                    : null

                  const contenu = (
                    <>
                      {imageUrl && (
                        <div className="relative w-full overflow-hidden border-b-2 border-gray-200 bg-gray-100 aspect-[4/3]">
                          <Image
                            src={imageUrl}
                            alt={titre}
                            fill
                            className="object-cover transition-transform duration-500 group-hover:scale-105"
                            sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
                            onError={(e) => { (e.target as HTMLImageElement).src = "/media/generique.jpg" }}
                          />
                        </div>
                      )}

                      <div className="flex flex-1 flex-col p-4 sm:p-5">
                        {!estActive && (
                          <p className="mb-2 inline-flex w-fit bg-primary px-2 py-1 text-[9px] font-bold uppercase tracking-[0.14em] text-white">
                            {isEn ? "Removed from the site" : "Retirée du site"}
                          </p>
                        )}
                        {dateLabel && (
                          <p className="text-[10px] font-semibold uppercase tracking-widest text-gray-400">
                            {dateLabel}
                          </p>
                        )}
                        <div className="mt-1.5 h-0.5 w-10 rounded-full bg-primary/70" aria-hidden />

                        {/* Le titre, absent de l'ancienne fiche : c'est lui qui
                            permet de parcourir la page du regard. */}
                        <h3 className="mt-3 line-clamp-3 text-[15px] font-bold leading-snug text-gray-900 transition-colors group-hover:text-primary sm:text-base">
                          {highlight(titre, search)}
                        </h3>

                        {extrait && (
                          <p className={`mt-2 text-[13px] leading-[1.65] text-neutral-500 ${imageUrl ? "line-clamp-3" : "line-clamp-6"}`}>
                            {highlight(extrait, search)}
                          </p>
                        )}

                        <div className="mt-auto pt-4">
                          <div className="flex justify-end border-t border-gray-100 pt-3">
                            <span className="inline-flex items-center gap-1 text-[11px] font-semibold uppercase tracking-widest text-primary">
                              {tCommon("readMore")}
                              <ArrowRight className="h-3 w-3 transition-transform group-hover:translate-x-0.5" />
                            </span>
                          </div>
                        </div>
                      </div>
                    </>
                  )

                  // Une fiche retirée reste visible pour l'administrateur,
                  // mais elle s'efface : le filet rouge et le contenu atténué
                  // disent au premier coup d'oeil qu'elle n'est plus en ligne.
                  const CADRE = estActive
                    ? "group flex h-full w-full flex-col overflow-hidden border-2 border-gray-200 bg-white text-left shadow-sm transition-all duration-300 hover:-translate-y-1 hover:shadow-xl"
                    : "group flex h-full w-full flex-col overflow-hidden border-2 border-primary/40 bg-neutral-50 text-left shadow-sm transition-all duration-300 hover:shadow-md [&_h3]:text-gray-500 [&_img]:opacity-40 [&_img]:grayscale"

                  return (
                    /* La commande d'image est posée en dehors de la fiche, et
                       non dedans : celle-ci est un bouton, et un bouton ne peut
                       pas en contenir un autre. */
                    <div key={action.id} className="relative flex">
                      {action.linkedInUrl ? (
                        <button
                          type="button"
                          onClick={() => onOpenLinkedIn?.(action.linkedInUrl!)}
                          className={`${CADRE} cursor-pointer touch-manipulation`}
                        >
                          {contenu}
                        </button>
                      ) : (
                        /* Sans publication d'origine, la fiche n'ouvre rien :
                           elle ne se donne donc pas l'apparence d'un lien. */
                        <div className={CADRE}>{contenu}</div>
                      )}

                      {connecte && (
                        <div className="absolute right-2 top-2 z-10 flex items-start gap-1.5">
                          <BoutonActivationActualite
                            id={action.id}
                            estActive={estActive}
                            onChange={(actif) => onActivationChange?.(action.id, actif)}
                          />
                          <BoutonImageActualite
                            id={action.id}
                            onChange={(url) => onImageChange?.(action.id, url)}
                          />
                        </div>
                      )}
                    </div>
                  )
                })}
              </div>
            )}

            {/* ── Sentinelle de defilement ─────────────────────────────────
                Le bouton n'est pas un ornement : au clavier, on n'atteint
                jamais le bas par le defilement, et l'observateur ne se
                declenche pas. Il reste donc la seule commande manuelle.
                `aria-live` annonce l'avancee sans deplacer le focus. */}
            {!loading && hasMore && (
              <div ref={sentinelle} className="mt-10 flex flex-col items-center gap-3">
                <button
                  type="button"
                  onClick={() => onLoadMore?.()}
                  className="inline-flex items-center gap-2 border border-neutral-200 bg-white px-5 py-3 text-[11px] font-semibold uppercase tracking-widest text-gray-600 transition-colors hover:border-primary hover:text-primary touch-manipulation"
                >
                  {t("loadMore")}
                  <ArrowRight className="h-3.5 w-3.5" />
                </button>
                <p className="text-[11px] font-semibold uppercase tracking-widest tabular-nums text-gray-400" aria-live="polite">
                  {actions.length} / {nombre}
                </p>
              </div>
            )}

            {/* Fin de flux : le compte confirme qu'il n'y a plus rien dessous,
                plutot que de laisser la page s'arreter sans explication. */}
            {!loading && !hasMore && actions.length > 0 && (
              <div className="mt-10 flex flex-col items-center gap-2">
                <div className="h-0.5 w-10 rounded-full bg-primary/70" aria-hidden />
                <p className="text-[11px] font-semibold uppercase tracking-widest tabular-nums text-gray-400">
                  {isEn
                    ? `All ${nombre} publications shown`
                    : `${nombre} publication${nombre > 1 ? "s" : ""} affichée${nombre > 1 ? "s" : ""}`}
                </p>
              </div>
            )}

          </div>
        </div>
      </section>

      {/* Modal LinkedIn */}
      <AnimatePresence>
        {modalLinkedInUrl && currentAction && (() => {
          const title = isEn ? currentAction.titleEn : currentAction.title
          return (
            <motion.div
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              exit={{ opacity: 0 }}
              transition={{ duration: 0.25 }}
              className="fixed inset-0 z-50 bg-black/70 backdrop-blur-sm flex items-end sm:items-center justify-center sm:p-6 lg:p-12"
              onClick={onCloseModal}
            >
              <motion.div
                initial={{ opacity: 0, y: 40 }}
                animate={{ opacity: 1, y: 0 }}
                exit={{ opacity: 0, y: 40 }}
                transition={{ duration: 0.28, ease: "easeOut" }}
                className="relative w-full sm:max-w-2xl flex flex-col overflow-hidden shadow-2xl h-[100dvh] sm:h-[min(90vh,680px)]"
                onClick={e => e.stopPropagation()}
              >

                {/* Barre de tête */}
                <div className="flex items-center gap-3 bg-white border-b border-neutral-100 px-4 py-3 flex-shrink-0">
                  <button
                    type="button"
                    onClick={onCloseModal}
                    className="flex-shrink-0 w-8 h-8 flex items-center justify-center bg-neutral-100 hover:bg-neutral-200 transition-colors rounded-full"
                  >
                    <X className="w-4 h-4 text-gray-700" />
                  </button>
                  <p className="flex-1 text-[10px] font-semibold uppercase tracking-widest text-gray-600 truncate">
                    {title}
                  </p>
                  <a
                    href={modalLinkedInUrl}
                    target="_blank"
                    rel="noopener noreferrer"
                    className="flex-shrink-0 inline-flex items-center gap-1.5 px-3 py-2 bg-primary text-white text-[10px] font-semibold uppercase tracking-widest hover:bg-primary/90 transition-colors"
                  >
                    <ExternalLink className="w-3 h-3" />
                    LinkedIn
                  </a>
                </div>

                {/* Iframe */}
                <div
                  className="flex-1 min-h-0 bg-white overflow-y-auto [&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar-track]:bg-gray-100 [&::-webkit-scrollbar-thumb]:bg-primary [&::-webkit-scrollbar-thumb]:rounded-full"
                  style={{ scrollbarColor: "#E52621 #f3f4f6", scrollbarWidth: "thin" }}
                >
                  {consent === "accepted" ? (
                    <iframe
                      key={modalLinkedInUrl}
                      src={getLinkedInEmbedUrl(modalLinkedInUrl)}
                      title="Post LinkedIn"
                      className="w-full border-0 block"
                      style={{ minHeight: "520px", height: "100%" }}
                      sandbox="allow-same-origin allow-scripts allow-popups allow-forms"
                    />
                  ) : (
                    <CookieIframePlaceholder
                      type="linkedin"
                      className="w-full"
                      style={{ minHeight: "520px" }}
                    />
                  )}
                </div>

                {/* Navigation prev/next */}
                {linkedInActions.length > 1 && (
                  <div className="flex items-center justify-between bg-white border-t border-neutral-200 px-5 py-3 flex-shrink-0">
                    <button
                      type="button"
                      onClick={modalPrev}
                      className="flex items-center gap-2 text-[11px] font-semibold uppercase tracking-widest text-primary hover:text-primary/70 transition-colors"
                    >
                      <ArrowLeft className="w-4 h-4" />
                      {isEn ? "Previous" : "Précédent"}
                    </button>
                    <span className="text-[11px] font-mono text-gray-400 font-bold">
                      {modalIndex + 1} / {linkedInActions.length}
                    </span>
                    <button
                      type="button"
                      onClick={modalNext}
                      className="flex items-center gap-2 text-[11px] font-semibold uppercase tracking-widest text-primary hover:text-primary/70 transition-colors"
                    >
                      {isEn ? "Next" : "Suivant"}
                      <ArrowRight className="w-4 h-4" />
                    </button>
                  </div>
                )}

              </motion.div>
            </motion.div>
          )
        })()}
      </AnimatePresence>
    </>
  )
}
