import { useEffect, useRef, useState } from 'react';
import { deletePost } from '../../lib/api';
import { confirmDialog, notify } from '../../lib/confirm';
import { buildCybersigil } from '../../lib/cybersigil';

// Per-plate sigil accent. Built post-mount (not during render) so the random
// markup never differs between SSR and hydration. Inert/display:none off the
// cybersigil theme; carves in on plate hover/focus via global.css.
function PlateSigil() {
  const [html, setHtml] = useState('');
  useEffect(() => { setHtml(buildCybersigil()); }, []);
  if (!html) return null;
  return (
    <div
      className="cs-plate-sig"
      aria-hidden="true"
      dangerouslySetInnerHTML={{ __html: html }}
    />
  );
}

const PAGE_SIZE = 9;

interface CoverImage {
  url: string;
  alt: string;
  w?: number;
  h?: number;
}

interface Post {
  slug: string;
  date: string;
  title?: string;
  excerpt?: string;
  summary?: string;
  tags: string[];
  draft: boolean;
  reading_time: number;
  cover_image?: CoverImage;
  image_count: number;
}

interface Props {
  posts: Post[];
  isAdmin?: boolean;
}

function formatSlug(slug: string) {
  if (!slug) return '';
  return slug
    .split('-')
    .map(w => w.charAt(0).toUpperCase() + w.slice(1))
    .join(' ');
}

function formatYear(date: string) {
  return new Date(date).getFullYear();
}

function formatMonth(date: string) {
  return new Date(date).toLocaleDateString('en-US', { month: 'short' }).toUpperCase();
}

// Deterministic salon-hang layout. Each tile gets a col-span (out of 12) and an aspect ratio.
// The cycle is chosen so the room reads asymmetric but balanced.
const LAYOUT_CYCLE: Array<{ col: number; aspect: string; tilt: number }> = [
  { col: 7, aspect: '4 / 3',  tilt: -0.4 },
  { col: 5, aspect: '3 / 4',  tilt:  0.3 },
  { col: 4, aspect: '4 / 5',  tilt: -0.2 },
  { col: 4, aspect: '1 / 1',  tilt:  0.5 },
  { col: 4, aspect: '4 / 5',  tilt: -0.6 },
  { col: 5, aspect: '1 / 1',  tilt:  0.2 },
  { col: 7, aspect: '5 / 4',  tilt: -0.3 },
  { col: 8, aspect: '16 / 10', tilt:  0.4 },
  { col: 4, aspect: '3 / 4',  tilt: -0.5 },
];

export default function PostList({ posts: initialPosts, isAdmin = false }: Props) {
  const [posts, setPosts] = useState(initialPosts);
  const [deleting, setDeleting] = useState<string | null>(null);
  const [visible, setVisible] = useState(() => Math.min(PAGE_SIZE, initialPosts.length));
  const sentinelRef = useRef<HTMLDivElement>(null);

  async function handleDelete(slug: string, title: string) {
    if (deleting) return;
    const ok = await confirmDialog({
      title: 'Take this off the wall?',
      message: `“${title}” will be removed from the catalogue. This cannot be undone.`,
      confirmLabel: 'Remove',
      cancelLabel: 'Keep',
    });
    if (!ok) return;
    setDeleting(slug);
    try {
      await deletePost(slug);
      setPosts(p => p.filter(x => x.slug !== slug));
    } catch (e) {
      notify(`Failed to remove: ${e instanceof Error ? e.message : 'unknown error'}`);
    } finally {
      setDeleting(null);
    }
  }

  useEffect(() => {
    setVisible(v => Math.min(Math.max(v, PAGE_SIZE), posts.length));
  }, [posts.length]);

  useEffect(() => {
    if (visible >= posts.length) return;
    const el = sentinelRef.current;
    if (!el) return;
    const io = new IntersectionObserver(
      entries => {
        if (entries.some(e => e.isIntersecting)) {
          setVisible(v => Math.min(v + PAGE_SIZE, posts.length));
        }
      },
      { rootMargin: '600px 0px' },
    );
    io.observe(el);
    return () => io.disconnect();
  }, [visible, posts.length]);

  if (posts.length === 0) {
    return null;
  }

  const shown = posts.slice(0, visible);
  const hasMore = visible < posts.length;

  return (
    <>
    <div className="grid grid-cols-1 md:grid-cols-12 gap-8 md:gap-x-10 md:gap-y-16">
      {shown.map((post, idx) => {
        const displayTitle = post.title || formatSlug(post.slug);
        const isDeleting = deleting === post.slug;
        const layout = LAYOUT_CYCLE[idx % LAYOUT_CYCLE.length];
        const hasCover = !!post.cover_image?.url;

        return (
          <article
            key={post.slug}
            className={`relative plate-enter md-col-span ${isDeleting ? 'opacity-40 pointer-events-none' : ''}`}
            style={{
              animationDelay: `${Math.min(idx * 80, 480)}ms`,
              ['--col-span' as any]: layout.col,
            }}
          >
            <a
              href={`/posts/${encodeURIComponent(post.slug)}`}
              className="block plate group"
              style={{ transform: `rotate(${layout.tilt}deg)` }}
              aria-label={`View ${displayTitle}`}
            >
              <div
                className={`plate-image ${hasCover ? 'is-natural' : ''}`}
                style={hasCover ? undefined : { aspectRatio: layout.aspect }}
              >
                {hasCover ? (
                  <img
                    src={post.cover_image!.url}
                    alt={post.cover_image!.alt || displayTitle}
                    width={post.cover_image!.w}
                    height={post.cover_image!.h}
                    loading={idx < 3 ? 'eager' : 'lazy'}
                    decoding={idx === 0 ? 'sync' : 'async'}
                    fetchPriority={idx === 0 ? 'high' : undefined}
                  />
                ) : (
                  <div
                    className="w-full h-full flex items-center justify-center text-[var(--rosewater)]"
                    style={{
                      background: `linear-gradient(135deg, var(--mauve), var(--mantle))`,
                    }}
                  >
                    <span className="font-display italic text-3xl opacity-70">
                      untitled
                    </span>
                  </div>
                )}
                {post.image_count > 1 && (
                  <span className="plate-tag-mini">
                    {post.image_count} plates
                  </span>
                )}
                {post.draft && (
                  <span className="plate-tag-mini" style={{ left: 18, right: 'auto', background: 'var(--peach)', color: 'var(--crust)' }}>
                    Sketch
                  </span>
                )}
              </div>

              <div className="plate-caption">
                <div className="plate-caption-title">{displayTitle}</div>
                {post.summary && (
                  <div className="plate-caption-summary">{post.summary}</div>
                )}
                <div className="plate-caption-meta">
                  <span>{formatMonth(post.date)}</span>
                  <span className="plate-caption-sep" aria-hidden="true">·</span>
                  <span>{formatYear(post.date)}</span>
                </div>
              </div>
            </a>

            {post.tags && post.tags.length > 0 && (
              <div className="flex flex-wrap gap-1.5 mt-3 px-1">
                {post.tags.slice(0, 4).map(tag => (
                  <span key={tag} className="chip">
                    {tag}
                  </span>
                ))}
              </div>
            )}

            {isAdmin && (
              <div className="absolute top-3 right-3 flex items-center gap-1.5 opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity">
                <a
                  href={`/admin/editor?edit=${encodeURIComponent(post.slug)}`}
                  onClick={e => e.stopPropagation()}
                  title="Edit"
                  aria-label={`Edit ${displayTitle}`}
                  className="btn btn--ghost btn--icon btn--sm"
                >
                  <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" /><path d="m15 5 4 4" /></svg>
                </a>
                <button
                  type="button"
                  onClick={e => { e.preventDefault(); e.stopPropagation(); handleDelete(post.slug, displayTitle); }}
                  disabled={isDeleting}
                  title="Remove"
                  aria-label={`Remove ${displayTitle}`}
                  className="btn btn--danger btn--icon btn--sm"
                >
                  <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 6h18" /><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6" /><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" /><line x1="10" x2="10" y1="11" y2="17" /><line x1="14" x2="14" y1="11" y2="17" /></svg>
                </button>
              </div>
            )}

            <PlateSigil />
          </article>
        );
      })}
    </div>
    {hasMore && (
      <div
        ref={sentinelRef}
        className="mt-12 md:mt-16 flex items-center justify-center text-[var(--subtext0)] font-display italic text-sm tracking-[0.2em] uppercase"
        aria-hidden="true"
      >
        <span className="opacity-60">arranging more…</span>
      </div>
    )}
    </>
  );
}
