"use client";

import { getLocation } from "@/lib/location";

import { useModule } from "@/lib/modules";

import { useCallback, useEffect, useRef, useState } from "react";
import Link from "next/link";
import { Newspaper, MapPin, Globe, ArrowRight } from "lucide-react";
import clsx from "clsx";

export type NewsItem = {
  id: string;
  title: string;
  source: string;
  url: string;
  publishedAt: string;
  image?: string;
};

const VISIBLE = 5;

/** A stable glyph per source, so image-less headlines still read as cards. */
const GLYPHS = ["📰", "🌍", "💼", "⚡", "🏛️", "🔬", "🎬", "⚽"];
function glyphFor(source: string) {
  let h = 0;
  for (let i = 0; i < source.length; i++) h = (h * 31 + source.charCodeAt(i)) & 0xffff;
  return GLYPHS[h % GLYPHS.length];
}

function ago(iso: string) {
  const diff = Date.now() - new Date(iso).getTime();
  if (Number.isNaN(diff)) return "";
  const m = Math.floor(diff / 60000);
  if (m < 1) return "just now";
  if (m < 60) return `${m}m`;
  const h = Math.floor(m / 60);
  if (h < 24) return `${h}h`;
  return `${Math.floor(h / 24)}d`;
}

export function NewsRail() {
  // Hidden when this module is switched off in System settings.
  const moduleOn = useModule("news");

  const [scope, setScope] = useState<"local" | "global">("local");
  const [items, setItems] = useState<NewsItem[]>([]);
  const [live, setLive] = useState(false);
  const [place, setPlace] = useState<{ country: string; city: string } | null>(null);
  const [askedLocation, setAskedLocation] = useState(false);
  const rotateRef = useRef<ReturnType<typeof setInterval> | null>(null);
  // Full pool; we show a window of it and rotate through.
  const poolRef = useRef<NewsItem[]>([]);
  const offsetRef = useRef(0);

  const load = useCallback(
    async (s: "local" | "global", p: { country: string; city: string } | null) => {
      const params = new URLSearchParams({ scope: s, limit: "20" });

  if (!moduleOn) return null;

      if (s === "local" && p) {
        params.set("country", p.country);
        if (p.city) params.set("city", p.city);
      }
      const res = await fetch(`/api/news?${params}`).catch(() => null);
      if (!res || !res.ok) return;
      const d = await res.json();
      poolRef.current = d.items ?? [];
      offsetRef.current = 0;
      setItems(poolRef.current.slice(0, VISIBLE));
      setLive(Boolean(d.live));
    },
    []
  );

  useEffect(() => {
    load(scope, place);
  }, [scope, place, load]);

  // Local is the default, so ask for location once on mount rather than
  // waiting for the person to switch tabs.
  useEffect(() => {
    if (place || askedLocation || typeof navigator === "undefined") return;
    setAskedLocation(true);
    getLocation().then(async (_c) => {
      if (!_c) return;
      const pos = { coords: { latitude: _c.lat, longitude: _c.lon } };
        const r = await fetch(
          `https://api.bigdatacloud.net/data/reverse-geocode-client?latitude=${pos.coords.latitude}&longitude=${pos.coords.longitude}&localityLanguage=en`
        ).catch(() => null);
        if (!r || !r.ok) return;
        const d = await r.json();
        setPlace({ country: d.countryCode || "", city: d.city || d.locality || "" });
      });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // Rotate the window so a new headline drops in on top every few seconds.
  useEffect(() => {
    if (rotateRef.current) clearInterval(rotateRef.current);
    rotateRef.current = setInterval(() => {
      const pool = poolRef.current;
      if (pool.length <= VISIBLE) return;
      offsetRef.current = (offsetRef.current + 1) % pool.length;
      const out: NewsItem[] = [];
      for (let i = 0; i < VISIBLE; i++) {
        out.push(pool[(offsetRef.current + i) % pool.length]);
      }
      setItems(out);
    }, 6000);
    return () => {
      if (rotateRef.current) clearInterval(rotateRef.current);
    };
  }, [items.length]);

  /** Ask for location only when the person opts into Local. */
  function enableLocal() {
    setScope("local");
    if (place || askedLocation || typeof navigator === "undefined") return;
    setAskedLocation(true);
    getLocation().then(async (_c) => {
      if (!_c) return;
      const pos = { coords: { latitude: _c.lat, longitude: _c.lon } };
        const { latitude, longitude } = pos.coords;
        // Keyless reverse geocode, so no credentials to manage.
        const r = await fetch(
          `https://api.bigdatacloud.net/data/reverse-geocode-client?latitude=${latitude}&longitude=${longitude}&localityLanguage=en`
        ).catch(() => null);
        if (!r || !r.ok) return;
        const d = await r.json();
        setPlace({ country: d.countryCode || "", city: d.city || d.locality || "" });
      })
      .catch(() => {
        // Denied or unavailable — the country-less local feed still works.
      });
  }

  return (
    <div className="rounded-2xl border border-neutral-200 dark:border-neutral-800 bg-white dark:bg-[#0c0c0c] p-4">
      <div className="flex items-center gap-2 mb-1">
        <Newspaper size={15} className="text-neutral-500" />
        <h3 className="font-semibold text-[15px] flex-1">Latest News</h3>
        {live && <span className="nw-live" title="Live headlines" />}
      </div>

      <div className="flex gap-1 mb-2">
        <button
          onClick={enableLocal}
          className={clsx("nw-tab flex items-center gap-1", scope === "local" && "on")}
        >
          <MapPin size={11} /> Local
        </button>
        <button
          onClick={() => setScope("global")}
          className={clsx("nw-tab flex items-center gap-1", scope === "global" && "on")}
        >
          <Globe size={11} /> Global
        </button>
      </div>

      {scope === "local" && !place && (
        <p className="text-[11px] text-neutral-400 mb-2">
          Allow location to see news near you.
        </p>
      )}
      {scope === "local" && place?.city && (
        <p className="text-[11px] text-neutral-400 mb-2">Near {place.city}</p>
      )}

      <div className="flex flex-col">
        {items.map((n) => (
          <a
            key={`${n.id}-${n.title}`}
            href={n.url === "#" ? undefined : n.url}
            target={n.url === "#" ? undefined : "_blank"}
            rel="noopener noreferrer"
            className="nw-item"
          >
            <span className="nw-thumb">
              {n.image ? (
                // eslint-disable-next-line @next/next/no-img-element
                <img src={n.image} alt="" loading="lazy" />
              ) : (
                <span className="nw-glyph">{glyphFor(n.source)}</span>
              )}
            </span>
            <span className="min-w-0 flex-1">
              <span className="nw-title">{n.title}</span>
              <span className="nw-meta block">
                {n.source} · {ago(n.publishedAt)}
              </span>
            </span>
          </a>
        ))}
        {items.length === 0 && (
          <p className="text-xs text-neutral-400 py-4 text-center">Loading headlines…</p>
        )}
      </div>

      <Link
        href="/news"
        className="flex items-center justify-center gap-1.5 mt-2 pt-2.5 border-t border-neutral-100 dark:border-neutral-900 text-xs font-bold text-neutral-500 hover:text-fuchsia-600 dark:hover:text-fuchsia-400 transition-colors"
      >
        All news <ArrowRight size={12} />
      </Link>
    </div>
  );
}
