import type { DefaultDocumentIDType, Where } from 'payload'
import type { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical'

import type { Post } from '@/payload-types'

import Link from 'next/link'
import configPromise from '@payload-config'
import { getPayload } from 'payload'
import { draftMode } from 'next/headers'
import React from 'react'

import { RichText } from '@/components/RichText'
import { PostsCollectionArchive } from '@/components/PostsCollectionArchive'
import { getArtikelHubPath } from '@/utilities/artikelHub'

type PostsArchiveBlockProps = {
  categories?: Array<{ id?: number | string } | number | string> | null
  currentCategorySlug?: string
  currentPage?: number
  introContent?: SerializedEditorState | null
  limit?: number | null
  populateBy?: 'collection' | 'selection' | null
  selectedDocs?: Array<{ value: Post | number | string }> | null
}

type AvailableCategory = {
  id: number | string
  slug: string
  title: string
}

const getAvailableCategories = (
  categories: PostsArchiveBlockProps['categories'],
): AvailableCategory[] => {
  const categoryMap = new Map<string, AvailableCategory>()

  for (const category of categories ?? []) {
    if (!category || typeof category !== 'object') {
      continue
    }

    if (!('id' in category) || category.id === undefined) {
      continue
    }

    if (!('slug' in category) || !category.slug || !('title' in category) || !category.title) {
      continue
    }

    categoryMap.set(String(category.id), {
      id: category.id,
      slug: String(category.slug),
      title: String(category.title),
    })
  }

  return Array.from(categoryMap.values())
}

export const PostsArchiveBlock: React.FC<
  PostsArchiveBlockProps & {
    id?: DefaultDocumentIDType
    className?: string
  }
> = async (props) => {
  const {
    id,
    categories,
    currentCategorySlug,
    currentPage = 1,
    introContent,
    limit: limitFromProps,
    populateBy,
    selectedDocs,
  } = props
  const { isEnabled: draft } = await draftMode()

  const limit = limitFromProps || 3
  const availableCategories = getAvailableCategories(categories)
  const activeCategory =
    availableCategories.find((category) => category.slug === currentCategorySlug) ?? null

  let posts: Post[] = []
  let pagination:
    | {
        hasNextPage: boolean
        hasPrevPage: boolean
        page: number
        totalPages: number
      }
    | null = null

  if (populateBy === 'collection') {
    const payload = await getPayload({ config: configPromise })

    const flattenedCategories = categories?.map((category: { id?: number | string } | number | string) =>
      typeof category === 'object' ? category.id : category,
    )

    const categoryWhere: Where | undefined =
      activeCategory
        ? {
            categories: {
              in: [activeCategory.id],
            },
          }
        : flattenedCategories && flattenedCategories.length > 0
        ? {
            categories: {
              in: flattenedCategories,
            },
          }
        : undefined

    const fetchedPosts = await payload.find({
      collection: 'posts',
      depth: 1,
      draft,
      limit,
      overrideAccess: draft,
      page: currentPage,
      sort: '-publishedAt',
      ...(categoryWhere ? { where: categoryWhere } : {}),
    })

    posts = fetchedPosts.docs
    pagination = {
      hasNextPage: fetchedPosts.hasNextPage,
      hasPrevPage: fetchedPosts.hasPrevPage,
      page: fetchedPosts.page || currentPage,
      totalPages: fetchedPosts.totalPages || 1,
    }
  } else if (selectedDocs?.length) {
    posts = selectedDocs
      .map((post: { value: Post | number | string }) =>
        typeof post.value === 'object' ? post.value : null,
      )
      .filter((post: Post | null): post is Post => Boolean(post))
  }

  return (
    <div className="my-16" id={`block-${id}`}>
      {introContent && (
        <div className="container mb-16">
          <RichText className="ml-0 max-w-3xl" data={introContent} enableGutter={false} />
        </div>
      )}
      {availableCategories.length > 0 && (
        <div className="container mb-8">
          <nav aria-label="Kategori artikel" className="flex flex-wrap items-center gap-3">
            <Link
              aria-current={!activeCategory ? 'page' : undefined}
              className={`rounded-full px-4 py-2 text-sm transition-colors ${
                !activeCategory
                  ? 'bg-foreground text-background'
                  : 'border border-border hover:bg-muted'
              }`}
              href={getArtikelHubPath(1)}
            >
              Semua
            </Link>
            {availableCategories.map((category) => {
              const isActive = category.slug === activeCategory?.slug

              return (
                <Link
                  aria-current={isActive ? 'page' : undefined}
                  className={`rounded-full px-4 py-2 text-sm transition-colors ${
                    isActive
                      ? 'bg-foreground text-background'
                      : 'border border-border hover:bg-muted'
                  }`}
                  href={getArtikelHubPath(1, category.slug)}
                  key={category.id}
                >
                  {category.title}
                </Link>
              )
            })}
          </nav>
        </div>
      )}
      <PostsCollectionArchive posts={posts} />
      {pagination && pagination.totalPages > 1 && (
        <nav aria-label="Artikel pagination" className="container mt-10">
          <div className="flex flex-wrap items-center gap-3">
            {pagination.hasPrevPage && (
              <Link
                className="rounded-full border border-border px-4 py-2 text-sm transition-colors hover:bg-muted"
                href={getArtikelHubPath(pagination.page - 1, activeCategory?.slug)}
              >
                Sebelumnya
              </Link>
            )}

            {Array.from({ length: pagination.totalPages }, (_, index) => index + 1).map((pageNumber) => {
              const isActive = pageNumber === pagination.page

              return (
                <Link
                  aria-current={isActive ? 'page' : undefined}
                  className={`rounded-full px-4 py-2 text-sm transition-colors ${
                    isActive
                      ? 'bg-foreground text-background'
                      : 'border border-border hover:bg-muted'
                  }`}
                  href={getArtikelHubPath(pageNumber, activeCategory?.slug)}
                  key={pageNumber}
                >
                  {pageNumber}
                </Link>
              )
            })}

            {pagination.hasNextPage && (
              <Link
                className="rounded-full border border-border px-4 py-2 text-sm transition-colors hover:bg-muted"
                href={getArtikelHubPath(pagination.page + 1, activeCategory?.slug)}
              >
                Selanjutnya
              </Link>
            )}
          </div>
        </nav>
      )}
    </div>
  )
}
