"use client";

/* eslint-disable @next/next/no-img-element -- Listing originals are served directly by the static Apache deployment. */

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { Listing, ListingCategory, listings as fallbackListings } from "./listings";

const categories: Array<"All finds" | ListingCategory> = [
  "All finds",
  "Tools & Tech",
  "Home & Office",
  "Mobility & Auto",
  "Games & Collectibles",
  "Outdoor & Recreation",
];

const ebayShopUrl = "https://www.ebay.com/sch/i.html?_ssn=dallasser87";
const ebayMessageUrl = "https://www.ebay.com/usr/dallasser87";
const catalogUrl = "/data/listings.json";

const ebayListingUrl = (listing: Listing) =>
  `${ebayShopUrl}&_nkw=${encodeURIComponent(listing.title)}`;

const oneDayInMs = 24 * 60 * 60 * 1000;

const wasListedInLastDay = (listing: Listing, currentTime: number) => {
  if (!listing.listedAt) return false;
  const listedTime = Date.parse(listing.listedAt);
  return Number.isFinite(listedTime) && currentTime - listedTime >= 0 && currentTime - listedTime <= oneDayInMs;
};

const isListingCategory = (value: unknown): value is ListingCategory =>
  typeof value === "string" && value !== "All finds" && categories.includes(value as ListingCategory);

const sanitizeListings = (value: unknown): Listing[] | null => {
  if (!Array.isArray(value)) return null;

  const clean = value.flatMap((item): Listing[] => {
    if (!item || typeof item !== "object") return [];
    const candidate = item as Partial<Listing>;
    const images = Array.isArray(candidate.images)
      ? candidate.images.filter((image): image is string => typeof image === "string" && image.startsWith("/listings/"))
      : [];

    if (
      typeof candidate.id !== "string" ||
      typeof candidate.title !== "string" ||
      typeof candidate.price !== "string" ||
      !isListingCategory(candidate.category) ||
      images.length === 0
    ) {
      return [];
    }

    const primary = typeof candidate.primary === "string" && images.includes(candidate.primary)
      ? candidate.primary
      : images[0];

    return [{
      id: candidate.id,
      title: candidate.title,
      shortTitle: typeof candidate.shortTitle === "string" && candidate.shortTitle.trim() ? candidate.shortTitle : candidate.title,
      price: candidate.price,
      listedAt: typeof candidate.listedAt === "string" ? candidate.listedAt : undefined,
      category: candidate.category,
      primary,
      images,
      summary: typeof candidate.summary === "string" ? candidate.summary : "",
      description: typeof candidate.description === "string" ? candidate.description : "",
      highlights: Array.isArray(candidate.highlights)
        ? candidate.highlights.filter((highlight): highlight is string => typeof highlight === "string" && highlight.trim().length > 0)
        : [],
      fulfillment: typeof candidate.fulfillment === "string" && candidate.fulfillment.trim() ? candidate.fulfillment : undefined,
    }];
  });

  return clean.length > 0 ? clean : null;
};

export default function Home() {
  const [catalogListings, setCatalogListings] = useState<Listing[]>(fallbackListings);
  const [category, setCategory] = useState<(typeof categories)[number]>("All finds");
  const [activeListing, setActiveListing] = useState<Listing | null>(null);
  const [activePhoto, setActivePhoto] = useState(0);
  const [shareLabel, setShareLabel] = useState("Share this item");
  const [shopShareLabel, setShopShareLabel] = useState("Copy shop link");
  const [itemShareUrl, setItemShareUrl] = useState("");
  const [shopShareUrl, setShopShareUrl] = useState("");
  const [currentTime, setCurrentTime] = useState(() => Date.now());
  const closeButtonRef = useRef<HTMLButtonElement>(null);
  const modalRef = useRef<HTMLElement>(null);
  const itemShareUrlRef = useRef<HTMLInputElement>(null);
  const shopShareUrlRef = useRef<HTMLInputElement>(null);
  const originatingCardRef = useRef<HTMLButtonElement | null>(null);
  const hadOpenListingRef = useRef(false);
  const shareResetTimerRef = useRef<number | null>(null);
  const shopShareResetTimerRef = useRef<number | null>(null);

  const totalPhotoCount = useMemo(
    () => catalogListings.reduce((total, listing) => total + listing.images.length, 0),
    [catalogListings],
  );
  const visibleListings = useMemo(
    () => category === "All finds" ? catalogListings : catalogListings.filter((item) => item.category === category),
    [catalogListings, category],
  );
  const newcomerListings = useMemo(
    () => catalogListings.filter((item) => wasListedInLastDay(item, currentTime)),
    [catalogListings, currentTime],
  );

  const closeListing = useCallback(() => {
    setActiveListing(null);
    setActivePhoto(0);
    setItemShareUrl("");
    window.history.replaceState(null, "", `${window.location.pathname}${window.location.search}`);
  }, []);

  useEffect(() => () => {
    if (shareResetTimerRef.current !== null) window.clearTimeout(shareResetTimerRef.current);
    if (shopShareResetTimerRef.current !== null) window.clearTimeout(shopShareResetTimerRef.current);
  }, []);

  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    if (window.location.pathname !== "/" || params.get("public") === "1") return;

    fetch("/cfs-admin/index.php?api=check", { cache: "no-store", credentials: "same-origin" })
      .then((response) => {
        if (response.ok) window.location.replace("/cfs-admin/index.php");
      })
      .catch(() => {
        // Public visitors are not allowed through the VPN-only admin gate.
      });
  }, []);

  useEffect(() => {
    let isMounted = true;

    fetch(`${catalogUrl}?v=${Date.now()}`, { cache: "no-store" })
      .then((response) => response.ok ? response.json() : Promise.reject(new Error(`Catalog request failed with ${response.status}`)))
      .then((data: unknown) => {
        const nextListings = sanitizeListings(data);
        if (isMounted && nextListings) setCatalogListings(nextListings);
      })
      .catch(() => {
        // Keep the built-in catalog if the editable JSON is temporarily unavailable.
      });

    return () => {
      isMounted = false;
    };
  }, []);

  useEffect(() => {
    const timer = window.setInterval(() => setCurrentTime(Date.now()), 60_000);
    return () => window.clearInterval(timer);
  }, []);

  useEffect(() => {
    if (!itemShareUrl) return;
    itemShareUrlRef.current?.focus();
    itemShareUrlRef.current?.select();
  }, [itemShareUrl]);

  useEffect(() => {
    if (!shopShareUrl) return;
    shopShareUrlRef.current?.focus();
    shopShareUrlRef.current?.select();
  }, [shopShareUrl]);

  useEffect(() => {
    if (activeListing) {
      hadOpenListingRef.current = true;
      return;
    }
    if (!hadOpenListingRef.current) return;

    hadOpenListingRef.current = false;
    const originatingCard = originatingCardRef.current;
    originatingCardRef.current = null;
    window.requestAnimationFrame(() => {
      if (originatingCard?.isConnected) originatingCard.focus();
    });
  }, [activeListing]);

  useEffect(() => {
    const syncFromHash = () => {
      const requested = window.location.hash.replace(/^#/, "");
      const match = catalogListings.find((item) => item.id === requested) ?? null;
      setActiveListing(match);
      setActivePhoto(0);
    };

    syncFromHash();
    window.addEventListener("hashchange", syncFromHash);
    window.addEventListener("popstate", syncFromHash);
    return () => {
      window.removeEventListener("hashchange", syncFromHash);
      window.removeEventListener("popstate", syncFromHash);
    };
  }, [catalogListings]);

  useEffect(() => {
    if (!activeListing) return;
    const previousOverflow = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    closeButtonRef.current?.focus();

    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === "Escape") {
        event.preventDefault();
        closeListing();
        return;
      }

      if (event.key === "Tab") {
        const modal = modalRef.current;
        if (!modal) return;
        const focusable = Array.from(modal.querySelectorAll<HTMLElement>(
          'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])',
        )).filter((element) => element.getClientRects().length > 0 && element.getAttribute("aria-hidden") !== "true");

        if (focusable.length === 0) {
          event.preventDefault();
          modal.focus();
          return;
        }

        const first = focusable[0];
        const last = focusable[focusable.length - 1];
        const focused = document.activeElement;
        if (event.shiftKey && (focused === first || !modal.contains(focused))) {
          event.preventDefault();
          last.focus();
        } else if (!event.shiftKey && (focused === last || !modal.contains(focused))) {
          event.preventDefault();
          first.focus();
        }
        return;
      }

      const target = event.target as HTMLElement | null;
      const isTextControl = target?.matches("input, textarea, select, [contenteditable='true']");
      if (isTextControl) return;
      if (event.key === "ArrowRight") {
        event.preventDefault();
        setActivePhoto((current) => (current + 1) % activeListing.images.length);
      }
      if (event.key === "ArrowLeft") {
        event.preventDefault();
        setActivePhoto((current) => (current - 1 + activeListing.images.length) % activeListing.images.length);
      }
    };

    document.addEventListener("keydown", handleKeyDown);
    return () => {
      document.body.style.overflow = previousOverflow;
      document.removeEventListener("keydown", handleKeyDown);
    };
  }, [activeListing, closeListing]);

  const openListing = (listing: Listing, originatingCard: HTMLButtonElement) => {
    originatingCardRef.current = originatingCard;
    setActiveListing(listing);
    setActivePhoto(0);
    setShareLabel("Share this item");
    setItemShareUrl("");
    window.history.pushState(null, "", `#${listing.id}`);
  };

  const copyUrl = async (url: string) => {
    try {
      if (!navigator.clipboard?.writeText) return false;
      await navigator.clipboard.writeText(url);
      return true;
    } catch {
      return false;
    }
  };

  const shareItem = async () => {
    if (!activeListing) return;
    const url = `${window.location.origin}${window.location.pathname}#${activeListing.id}`;
    if (navigator.share) {
      try {
        await navigator.share({ title: activeListing.title, text: `${activeListing.title} — ${activeListing.price}`, url });
        return;
      } catch {
        // A dismissed or unavailable share sheet falls through to copy/manual selection.
      }
    }
    if (await copyUrl(url)) {
      setItemShareUrl("");
      setShareLabel("Link copied");
      if (shareResetTimerRef.current !== null) window.clearTimeout(shareResetTimerRef.current);
      shareResetTimerRef.current = window.setTimeout(() => setShareLabel("Share this item"), 1800);
    } else {
      if (shareResetTimerRef.current !== null) window.clearTimeout(shareResetTimerRef.current);
      setShareLabel("Copy the link below");
      setItemShareUrl(url);
    }
  };

  const shareShop = async () => {
    const url = `${window.location.origin}${window.location.pathname}`;
    if (await copyUrl(url)) {
      setShopShareUrl("");
      setShopShareLabel("Shop link copied");
      if (shopShareResetTimerRef.current !== null) window.clearTimeout(shopShareResetTimerRef.current);
      shopShareResetTimerRef.current = window.setTimeout(() => setShopShareLabel("Copy shop link"), 1800);
    } else {
      if (shopShareResetTimerRef.current !== null) window.clearTimeout(shopShareResetTimerRef.current);
      setShopShareLabel("Copy the link below");
      setShopShareUrl(url);
    }
  };

  return (
    <main>
      <header className="site-header">
        <a className="brand" href="#top" aria-label="Carrollton For Sale home">
          <span className="brand-mark">CFS</span>
          <span>Carrollton For Sale</span>
        </a>
        <nav aria-label="Primary navigation">
          <a href="#newcomers">New arrivals</a>
          <a href="#finds">Shop the finds</a>
          <a href="#how-it-works">How it works</a>
          <a className="nav-pill" href="#contact">Contact</a>
        </nav>
      </header>

      <section className="hero" id="top">
        <div className="hero-copy">
          <p className="eyebrow">A neighborhood secondhand shop</p>
          <h1>Good finds.<br />Right here in Carrollton.</h1>
          <p className="intro">
            Useful gear, practical home pieces, and one-of-a-kind finds, with Carrollton pickup and shipping on many items.
          </p>
          <div className="hero-actions">
            <a className="primary-button" href="#finds">Browse what’s available <span aria-hidden="true">↓</span></a>
            <span className="micro-note">Real photos of every listed item.</span>
          </div>
        </div>
        <div className="hero-card" aria-label="Shipping and local pickup information">
          <p className="handwritten">ship it or pick it up</p>
          <div className="pickup-badge">
            <span className="pickup-pin" aria-hidden="true">●</span>
            <span><strong>Pickup available</strong><br />with shipping on many items</span>
          </div>
          <div className="hero-stats">
            <span><strong>{catalogListings.length}</strong> finds</span>
            <span><strong>$10</strong> starting at</span>
            <span><strong>30</strong> day returns</span>
          </div>
          <p>Every item has real photos, clear details, and online checkout through our eBay shop.</p>
          <div className="sunburst" aria-hidden="true">★</div>
        </div>
      </section>

      <div className="ticker" aria-label="Store promises">
        <div>
          <span>SHIPPING ON MANY ITEMS</span><b>✦</b><span>CARROLLTON PICKUP</span><b>✦</b><span>RETURNS ACCEPTED</span><b>✦</b><span>{totalPhotoCount} REAL PHOTOS</span>
        </div>
      </div>

      <section className="newcomers" id="newcomers" aria-labelledby="newcomers-title">
        <div className="section-heading newcomer-heading">
          <div>
            <p className="eyebrow">New in the last 24 hours</p>
            <h2 id="newcomers-title">Newcomers</h2>
          </div>
          <span className="inventory-note">
            {newcomerListings.length > 0 ? `${newcomerListings.length} fresh listings` : "No fresh listings right now"}
          </span>
        </div>

        {newcomerListings.length > 0 ? (
          <div className="newcomer-rail" aria-label="New arrivals added in the last 24 hours">
            {newcomerListings.map((item) => (
              <article className="newcomer-card" key={item.id}>
                <button className="newcomer-button" type="button" onClick={(event) => openListing(item, event.currentTarget)} aria-label={`View new arrival ${item.title}`}>
                  <div className="newcomer-photo">
                    <img src={item.primary} alt={item.title} loading="lazy" />
                    <span className="price-tag">{item.price}</span>
                  </div>
                  <div className="newcomer-copy">
                    <span>New arrival</span>
                    <h3>{item.shortTitle}</h3>
                    <p>{item.summary}</p>
                  </div>
                </button>
              </article>
            ))}
          </div>
        ) : (
          <p className="newcomer-empty">No listings were added in the last 24 hours. The newest available items are still below.</p>
        )}
      </section>

      <section className="featured" id="finds">
        <div className="section-heading">
          <div>
            <p className="eyebrow">Fresh from the garage</p>
            <h2>Today’s good finds</h2>
          </div>
          <span className="inventory-note">{catalogListings.length} items available</span>
        </div>

        <div className="filters" aria-label="Filter listings">
          {categories.map((option) => (
            <button
              type="button"
              className={category === option ? "filter active" : "filter"}
              aria-pressed={category === option}
              onClick={() => setCategory(option)}
              key={option}
            >
              {option}
            </button>
          ))}
        </div>

        <div className="product-grid" aria-live="polite">
          {visibleListings.map((item, index) => (
            <article className={`product-card card-${(index % 3) + 1}`} key={item.id}>
              <button className="card-button" type="button" onClick={(event) => openListing(item, event.currentTarget)} aria-label={`View ${item.title}`}>
                <div className="product-photo">
                  <img src={item.primary} alt={item.title} loading="lazy" />
                  <span className="price-tag">{item.price}</span>
                  <span className="available-tag">Available</span>
                  {wasListedInLastDay(item, currentTime) && <span className="new-badge">New</span>}
                </div>
                <div className="product-copy">
                  <p>{item.category}</p>
                  <h3>{item.shortTitle}</h3>
                  <span className="view-link">View details <b aria-hidden="true">↗</b></span>
                </div>
              </button>
            </article>
          ))}
        </div>
      </section>

      <section className="how-it-works" id="how-it-works">
        <div className="how-title">
          <p className="eyebrow">The simple version</p>
          <h2>See it. Buy it. Ship it when available or pick it up.</h2>
          <p>Every listing shows the exact item, price, features, and included pieces.</p>
        </div>
        <ol className="steps">
          <li><span>01</span><div><h3>Browse the real photos</h3><p>Open an item to view its full photo set and key features.</p></div></li>
          <li><span>02</span><div><h3>Buy securely online</h3><p>Use eBay checkout to pay and receive purchase confirmation.</p></div></li>
          <li><span>03</span><div><h3>Choose delivery</h3><p>Select shipping where offered or arrange local pickup in Carrollton.</p></div></li>
        </ol>
      </section>

      <section className="contact-panel" id="contact">
        <div>
          <p className="eyebrow">Found your next good find?</p>
          <h2>Buy online or ask the seller directly.</h2>
        </div>
        <div className="contact-copy">
          <p>Pay through the eBay shop, then choose shipping where offered or arrange Carrollton pickup. Use the seller profile there to send questions about any item.</p>
          <div className="contact-actions">
            <a className="primary-button" href={ebayShopUrl} target="_blank" rel="noreferrer">Shop on eBay <span aria-hidden="true">↗</span></a>
            <a className="light-button" href={ebayMessageUrl} target="_blank" rel="noreferrer">Message seller <span aria-hidden="true">↗</span></a>
            <button className="light-button" type="button" onClick={shareShop}>{shopShareLabel}</button>
          </div>
          {shopShareUrl && (
            <div className="copy-fallback" role="status">
              <label htmlFor="shop-share-url">Copy this shop link:</label>
              <input
                id="shop-share-url"
                ref={shopShareUrlRef}
                type="url"
                value={shopShareUrl}
                readOnly
                onFocus={(event) => event.currentTarget.select()}
                onClick={(event) => event.currentTarget.select()}
              />
            </div>
          )}
        </div>
      </section>

      <footer>
        <a className="brand footer-brand" href="#top"><span className="brand-mark">CFS</span><span>Carrollton For Sale</span></a>
        <p>Secondhand finds with Carrollton pickup, shipping on many items, and 30-day returns.</p>
        <a href="#top">Back to top ↑</a>
      </footer>

      {activeListing && (
        <div className="modal-backdrop" role="presentation" onMouseDown={(event) => event.target === event.currentTarget && closeListing()}>
          <section className="listing-modal" role="dialog" aria-modal="true" aria-labelledby="listing-title" ref={modalRef} tabIndex={-1}>
            <button className="modal-close" type="button" onClick={closeListing} ref={closeButtonRef} aria-label="Close item details">×</button>
            <div className="modal-gallery">
              <div className="modal-main-photo">
                <img src={activeListing.images[activePhoto]} alt={`${activeListing.title}, view ${activePhoto + 1} of ${activeListing.images.length}`} />
                <span className="photo-count">{activePhoto + 1} / {activeListing.images.length}</span>
                {activeListing.images.length > 1 && (
                  <>
                    <button className="photo-arrow previous" type="button" onClick={() => setActivePhoto((activePhoto - 1 + activeListing.images.length) % activeListing.images.length)} aria-label="Previous photo">←</button>
                    <button className="photo-arrow next" type="button" onClick={() => setActivePhoto((activePhoto + 1) % activeListing.images.length)} aria-label="Next photo">→</button>
                  </>
                )}
              </div>
              <div className="thumbnail-row" role="group" aria-label={`Choose a photo for ${activeListing.title}`}>
                {activeListing.images.map((image, index) => (
                  <button
                    type="button"
                    className={index === activePhoto ? "thumbnail active" : "thumbnail"}
                    onClick={() => setActivePhoto(index)}
                    aria-label={`Show photo ${index + 1}`}
                    aria-pressed={index === activePhoto}
                    aria-current={index === activePhoto ? "true" : undefined}
                    key={image}
                  >
                    <img src={image} alt="" loading="lazy" />
                  </button>
                ))}
              </div>
            </div>
            <div className="modal-copy">
              <div className="modal-meta"><span>{activeListing.category}</span><span>Available</span></div>
              <h2 id="listing-title">{activeListing.title}</h2>
              <div className="modal-price">{activeListing.price}</div>
              <p className="modal-summary">{activeListing.summary}</p>
              <p>{activeListing.description}</p>
              <ul>
                {activeListing.highlights.map((highlight) => <li key={highlight}>{highlight}</li>)}
              </ul>
              <div className="modal-actions">
                <a className="primary-button" href={ebayListingUrl(activeListing)} target="_blank" rel="noreferrer">Buy online <span aria-hidden="true">↗</span></a>
                <a className="light-button" href={ebayMessageUrl} target="_blank" rel="noreferrer">Ask the seller</a>
                <button className="light-button share-button" type="button" onClick={shareItem}>{shareLabel}</button>
                <span>{activeListing.fulfillment ?? "See the linked eBay listing for available order options."}</span>
              </div>
              {itemShareUrl && (
                <div className="copy-fallback" role="status">
                  <label htmlFor="item-share-url">Copy this item link:</label>
                  <input
                    id="item-share-url"
                    ref={itemShareUrlRef}
                    type="url"
                    value={itemShareUrl}
                    readOnly
                    onFocus={(event) => event.currentTarget.select()}
                    onClick={(event) => event.currentTarget.select()}
                  />
                </div>
              )}
            </div>
          </section>
        </div>
      )}
    </main>
  );
}
