"use client";

import { FormEvent, KeyboardEvent, useEffect, useRef, useState } from "react";
import Image from "next/image";
import type { PortfolioDetail, PortfolioFailure, PortfolioImage, PortfolioItem, PortfolioTaxonomy, PortfolioTopic } from "@/app/lib/portfolio";
import { getPortfolioDetail, getPortfolioPage, getPortfolioTopicPage, recordPortfolioView } from "@/app/lib/portfolio";
import styles from "./portfolio.module.css";

type Filters = { category: string; theme: string; type: string; q: string; page: number };

const failureMessage = "Portfolio API hiện chưa kết nối được. Hãy kiểm tra backend NestJS và cấu hình DATABASE_URL.";

export default function PortfolioBrowser({
  initialItems,
  initialPagination,
  initialFilters: pageFilters,
  initialError,
  taxonomy,
  topic,
  homePreview = false,
}: {
  initialItems: PortfolioItem[];
  initialPagination: { page: number; pageSize: number; total: number; totalPages: number };
  initialFilters: Filters;
  initialError: PortfolioFailure | null;
  taxonomy: PortfolioTaxonomy;
  topic?: PortfolioTopic;
  homePreview?: boolean;
}) {
  const [items, setItems] = useState(initialItems);
  const [pagination, setPagination] = useState(initialPagination);
  const [filters, setFilters] = useState(pageFilters);
  const [draft, setDraft] = useState(pageFilters);
  const [error, setError] = useState<PortfolioFailure | null>(initialError);
  const [loading, setLoading] = useState(false);
  const [selectedSlug, setSelectedSlug] = useState<string | null>(null);
  const [detail, setDetail] = useState<PortfolioDetail | null>(null);
  const [detailLoading, setDetailLoading] = useState(false);
  const [detailError, setDetailError] = useState(false);
  const [relatedItems, setRelatedItems] = useState<PortfolioItem[]>([]);
  const [relatedLoading, setRelatedLoading] = useState(false);
  const [viewCounts, setViewCounts] = useState<Record<string, number>>({});
  const [imageIndex, setImageIndex] = useState(0);
  const [zoomed, setZoomed] = useState(false);
  const dialogRef = useRef<HTMLDialogElement>(null);
  const closeButtonRef = useRef<HTMLButtonElement>(null);
  const detailRequestId = useRef(0);
  const relatedCache = useRef(new Map<string, PortfolioItem[]>());

  const activeImageList: PortfolioImage[] = detail?.images.length
    ? detail.images
    : detail
      ? [{ id: detail.id, url: detail.coverUrl, alt: detail.coverAlt, width: detail.coverWidth, height: detail.coverHeight, sortOrder: 0 }]
      : [];

  useEffect(() => {
    if (!selectedSlug) return;
    const htmlOverflow = document.documentElement.style.overflow;
    const bodyOverflow = document.body.style.overflow;
    document.documentElement.style.overflow = "hidden";
    document.body.style.overflow = "hidden";
    return () => {
      document.documentElement.style.overflow = htmlOverflow;
      document.body.style.overflow = bodyOverflow;
    };
  }, [selectedSlug]);

  async function load(next: Filters) {
    setLoading(true);
    setError(null);
    setFilters(next);
    setDraft(next);
    const params = new URLSearchParams();
    if (next.category) params.set("category", next.category);
    if (next.theme) params.set("theme", next.theme);
    if (next.type) params.set("type", next.type);
    if (next.q.trim()) params.set("q", next.q.trim());
    params.set("page", String(next.page));

    const query = params.toString();
    const basePath = topic ? `/portfolio/${encodeURIComponent(topic.slug)}` : "/portfolio";
    window.history.replaceState(null, "", query ? `${basePath}?${query}` : basePath);
    const result = topic
      ? await getPortfolioTopicPage(topic.slug, { category: next.category, type: next.type, page: next.page, pageSize: pagination.pageSize })
      : await getPortfolioPage({ ...next, pageSize: pagination.pageSize });
    setItems(result.items);
    setPagination({ page: result.page, pageSize: result.pageSize, total: result.total, totalPages: Math.ceil(result.total / result.pageSize) });
    setError(result.error);
    setLoading(false);
  }

  function submitFilters(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    void load({ ...draft, page: 1 });
  }

  async function loadDetail(slug: string, requestView: boolean, fallbackItem?: PortfolioItem) {
    const requestId = ++detailRequestId.current;
    setDetail(fallbackItem ? {
      ...fallbackItem,
      description: null,
      images: [{ id: fallbackItem.id, url: fallbackItem.coverUrl, alt: fallbackItem.coverAlt, width: fallbackItem.coverWidth, height: fallbackItem.coverHeight, sortOrder: 0 }],
    } : null);
    setDetailLoading(true);
    setDetailError(false);
    setRelatedLoading(true);
    setRelatedItems(fallbackItem
      ? items.filter((item) => item.slug !== fallbackItem.slug && item.theme.slug === fallbackItem.theme.slug)
          .sort((a, b) => Number(b.category.slug === fallbackItem.category.slug) - Number(a.category.slug === fallbackItem.category.slug))
          .slice(0, 4)
      : []);
    setImageIndex(0);
    setZoomed(false);

    if (requestView) {
      void recordPortfolioView(slug).then((views) => {
        setViewCounts((current) => ({ ...current, [slug]: views }));
        setItems((current) => current.map((item) => item.slug === slug ? { ...item, views } : item));
        setDetail((current) => current?.slug === slug ? { ...current, views } : current);
      }).catch(() => undefined);
    }

    try {
      const result = await getPortfolioDetail(slug);
      if (requestId === detailRequestId.current) {
        setDetail(result);
        setDetailLoading(false);
        let topicItems = relatedCache.current.get(result.theme.slug);
        if (!topicItems) {
          const page = await getPortfolioPage({ theme: result.theme.slug, page: 1, pageSize: 24 });
          topicItems = page.error
            ? items.filter((item) => item.theme.slug === result.theme.slug)
            : page.items;
          if (!page.error) relatedCache.current.set(result.theme.slug, topicItems);
        }
        if (requestId !== detailRequestId.current) return;
        const related = topicItems
          .filter((item) => item.slug !== result.slug)
          .sort((a, b) => Number(b.category.slug === result.category.slug) - Number(a.category.slug === result.category.slug))
          .slice(0, 4);
        setRelatedItems(related);
      }
    } catch {
      if (requestId === detailRequestId.current && !fallbackItem) setDetailError(true);
    } finally {
      if (requestId === detailRequestId.current) {
        setDetailLoading(false);
        setRelatedLoading(false);
      }
    }
  }

  function openItem(item: PortfolioItem) {
    setSelectedSlug(item.slug);
    if (dialogRef.current && !dialogRef.current.open) dialogRef.current.showModal();
    void loadDetail(item.slug, true, item);
  }

  function openRelatedItem(item: PortfolioItem) {
    setSelectedSlug(item.slug);
    setZoomed(false);
    void loadDetail(item.slug, true, item);
    requestAnimationFrame(() => closeButtonRef.current?.focus());
  }

  function closeLightbox() {
    detailRequestId.current += 1;
    if (dialogRef.current?.open) dialogRef.current.close();
    setSelectedSlug(null);
    setDetail(null);
    setDetailLoading(false);
    setDetailError(false);
    setRelatedItems([]);
    setRelatedLoading(false);
    setZoomed(false);
  }

  function moveImage(direction: -1 | 1) {
    if (!activeImageList.length) return;
    setImageIndex((current) => (current + direction + activeImageList.length) % activeImageList.length);
    setZoomed(false);
  }

  function onLightboxKeyDown(event: KeyboardEvent<HTMLDialogElement>) {
    if (event.key === "ArrowLeft") {
      event.preventDefault();
      moveImage(-1);
    }
    if (event.key === "ArrowRight") {
      event.preventDefault();
      moveImage(1);
    }
  }

  return (
    <>
      {!homePreview && <section className={`${styles.portfolioHero} section-wrap`} aria-labelledby="portfolio-title">
        <p className="eyebrow"><span className="eyebrow__dot" /> JUNX DESIGN · {topic ? "CHỦ ĐỀ" : "THƯ VIỆN TÁC PHẨM"}</p>
        <div className={styles.heroTitleRow}>
          <h1 id="portfolio-title">{topic ? topic.name : <>Portfolio<span>.</span></>}</h1>
          <p>{topic ? `Tác phẩm JUNX DESIGN thuộc chủ đề ${topic.name}.` : "Không gian lưu trữ những lựa chọn hình ảnh và ý tưởng thiết kế của JUNX."}</p>
        </div>
        <div className={styles.heroRule}><span>{topic ? "DANH MỤC · LOẠI THIẾT KẾ" : "CHỌN LỌC THEO CÁCH BẠN TÌM"}</span><span>JX — 01</span></div>
      </section>}

      <section className={homePreview ? styles.homePreview : `${styles.portfolioLibrary} section-wrap`} aria-label={homePreview ? "Tác phẩm nổi bật của chủ đề" : "Thư viện thiết kế"}>
        {!homePreview && <form className={`${styles.filters}${topic ? ` ${styles.topicFilters}` : ""}`} onSubmit={submitFilters} aria-label="Lọc tác phẩm">
          {!topic && <label className={styles.searchField}>
            <span>Tìm tác phẩm</span>
            <input value={draft.q} onChange={(event) => setDraft({ ...draft, q: event.target.value })} placeholder="Từ khóa..." maxLength={100} />
          </label>}
          <label>
            <span>Danh mục</span>
            <select value={draft.category} onChange={(event) => setDraft({ ...draft, category: event.target.value })}>
              <option value="">Tất cả danh mục</option>
              {(topic?.categories ?? taxonomy.categories).map((term) => <option value={term.slug} key={term.slug}>{term.name}</option>)}
            </select>
          </label>
          {!topic && <label>
            <span>Chủ đề</span>
            <select value={draft.theme} onChange={(event) => setDraft({ ...draft, theme: event.target.value })}>
              <option value="">Tất cả chủ đề</option>
              {taxonomy.themes.map((term) => <option value={term.slug} key={term.slug}>{term.name}</option>)}
            </select>
          </label>}
          <label>
            <span>Loại thiết kế</span>
            <select value={draft.type} onChange={(event) => setDraft({ ...draft, type: event.target.value })}>
              <option value="">Tất cả loại</option>
              {(topic?.designTypes ?? taxonomy.designTypes).map((term) => <option value={term.slug} key={term.slug}>{term.name}</option>)}
            </select>
          </label>
          <button className={styles.filterButton} type="submit">Lọc tác phẩm <span aria-hidden="true">↗</span></button>
        </form>}

        <div className={styles.results} aria-live="polite" aria-busy={loading}>
          {loading && items.length === 0 && (
            <div className={`${styles.grid} ${styles.skeletonGrid}`} aria-label="Đang tải tác phẩm">
              {Array.from({ length: 8 }, (_, index) => <div className={styles.skeleton} key={index}><span /><i /><i /></div>)}
            </div>
          )}

          {error && (
            <div className={`${styles.state} ${styles.errorState}`} role="alert">
              <span className={styles.stateIndex}>01 — KẾT NỐI</span>
              <h2>Chưa tải được thư viện.</h2>
              <p>{failureMessage}</p>
              <button className="text-action" type="button" onClick={() => void load(filters)}>Thử lại <span>↗</span></button>
            </div>
          )}

          {taxonomy.error && !error && <p className={styles.taxonomyWarning} role="status">Không thể tải bộ lọc danh mục lúc này.</p>}

          {!loading && !error && items.length === 0 && (
            <div className={styles.state}>
              <span className={styles.stateIndex}>00 — THƯ VIỆN</span>
              <h2>Chưa có tác phẩm phù hợp.</h2>
              <p>Thử đổi bộ lọc hoặc quay lại sau khi thư viện được cập nhật.</p>
            </div>
          )}

          {items.length > 0 && (
            <>
              {!homePreview && <p className={styles.count}>{pagination.total} tác phẩm <span>·</span> trang {pagination.page} / {Math.max(1, pagination.totalPages)}</p>}
              <div className={`${styles.grid}${loading ? ` ${styles.gridLoading}` : ""}`}>
                {items.map((item, index) => (
                  <button className={styles.card} type="button" onClick={() => openItem(item)} key={item.id} aria-label={`Mở hình ${item.title}`}>
                    <span className={styles.cardImage}>
                      <Image
                        src={item.coverUrl}
                        alt={item.coverAlt}
                        width={item.coverWidth}
                        height={item.coverHeight}
                        sizes="(max-width: 767px) 50vw, (max-width: 1024px) 33vw, 25vw"
                        priority={index === 0 && pagination.page === 1}
                        loading={index === 0 && pagination.page === 1 ? undefined : index === 1 && pagination.page === 1 ? "eager" : "lazy"}
                        quality={88}
                        decoding="async"
                      />
                      <span className={styles.cardViews}>{item.views} lượt xem</span>
                      <span className={styles.cardOpen} aria-hidden="true">↗</span>
                    </span>
                  </button>
                ))}
              </div>
              {!homePreview && pagination.totalPages > 1 && (
                <nav className={styles.pagination} aria-label="Phân trang tác phẩm">
                  <button type="button" className="text-action" disabled={pagination.page <= 1 || loading} onClick={() => void load({ ...filters, page: pagination.page - 1 })}>← Trước</button>
                  <span>{String(pagination.page).padStart(2, "0")} / {String(pagination.totalPages).padStart(2, "0")}</span>
                  <button type="button" className="text-action" disabled={pagination.page >= pagination.totalPages || loading} onClick={() => void load({ ...filters, page: pagination.page + 1 })}>Tiếp theo <span>↗</span></button>
                </nav>
              )}
            </>
          )}
        </div>
      </section>

      <dialog
        ref={dialogRef}
        className={styles.lightbox}
        aria-label="Xem ảnh tác phẩm"
        onClose={() => {
          detailRequestId.current += 1;
          setSelectedSlug(null);
          setDetail(null);
          setDetailLoading(false);
          setDetailError(false);
          setRelatedItems([]);
          setRelatedLoading(false);
          setZoomed(false);
        }}
        onKeyDown={onLightboxKeyDown}
        onClick={(event) => { if (event.target === event.currentTarget) closeLightbox(); }}
      >
        <button ref={closeButtonRef} className={styles.lightboxClose} type="button" onClick={closeLightbox} aria-label="Đóng ảnh">×</button>
        {detailLoading && <p className={styles.lightboxMessage} role="status">Đang tải hình ảnh…</p>}
        {detailError && (
          <div className={styles.lightboxMessage} role="alert">
            <p>Không tải được ảnh. Vui lòng thử lại.</p>
            {selectedSlug && <button className="text-action" type="button" onClick={() => void loadDetail(selectedSlug, false)}>Thử lại <span>↗</span></button>}
          </div>
        )}
        {detail && activeImageList[imageIndex] && (
          <div className={styles.lightboxContent}>
            <div className={`${styles.lightboxImageWrap}${zoomed ? ` ${styles.lightboxImageWrapZoomed}` : ""}`}>
              {activeImageList.length > 1 && <button className={`${styles.lightboxArrow} ${styles.lightboxArrowPrev}`} type="button" onClick={() => moveImage(-1)} aria-label="Ảnh trước">←</button>}
              <button className={styles.zoomButton} type="button" onClick={() => setZoomed((current) => !current)} aria-label={zoomed ? "Thu nhỏ ảnh" : "Phóng to ảnh"}>
                <Image className={`${styles.lightboxImage}${zoomed ? ` ${styles.lightboxImageZoomed}` : ""}`} src={activeImageList[imageIndex].url} alt={activeImageList[imageIndex].alt} width={activeImageList[imageIndex].width} height={activeImageList[imageIndex].height} sizes="(max-width: 767px) 96vw, 82vw" priority quality={95} decoding="async" draggable={false} onContextMenu={(event) => event.preventDefault()} onDragStart={(event) => event.preventDefault()} />
              </button>
              {activeImageList.length > 1 && <button className={`${styles.lightboxArrow} ${styles.lightboxArrowNext}`} type="button" onClick={() => moveImage(1)} aria-label="Ảnh tiếp theo">→</button>}
            </div>
            <div className={styles.lightboxCaption}>
              <div><p>{detail.category.name} · {detail.theme.name} · {detail.designType.name}</p><h2>{detail.title}</h2>{detail.description && <p>{detail.description}</p>}</div>
              <div className={styles.lightboxStats}><span>{viewCounts[detail.slug] ?? detail.views} lượt xem</span>{activeImageList.length > 1 && <span>{String(imageIndex + 1).padStart(2, "0")} / {String(activeImageList.length).padStart(2, "0")}</span>}</div>
            </div>
            <section className={styles.relatedWorks} aria-label="Tác phẩm liên quan">
              <div className={styles.relatedHeading}><h3>Tác phẩm liên quan</h3>{relatedLoading && <span role="status">Đang tải…</span>}</div>
              {relatedItems.length > 0 && <div className={styles.relatedGrid}>
                {relatedItems.map((item) => <button key={item.id} type="button" className={styles.relatedCard} onClick={() => openRelatedItem(item)} aria-label={`Xem tác phẩm liên quan: ${item.title}`}>
                  <span className={styles.relatedImage}><Image src={item.coverUrl} alt={item.coverAlt} width={item.coverWidth} height={item.coverHeight} sizes="(max-width: 767px) 42vw, 20vw" loading="lazy" quality={82} decoding="async" draggable={false} onContextMenu={(event) => event.preventDefault()} onDragStart={(event) => event.preventDefault()} /></span>
                  <span className={styles.relatedTitle}>{item.title}</span>
                </button>)}
              </div>}
              {!relatedLoading && relatedItems.length === 0 && <p className={styles.relatedEmpty}>Chưa có tác phẩm liên quan.</p>}
            </section>
          </div>
        )}
      </dialog>
    </>
  );
}
