import type { ShopArchiveBlock } from '@/payload-types'
import type { ShopFacetCounts } from '@/lib/shop/queryProducts'
import type { ReactNode } from 'react'
import type { ShopFilterLabels } from '@/lib/shop/filterLabels'
import type { ParsedShopSearchParams } from '@/utilities/shopParams'

import { Suspense } from 'react'

import { Search } from '@/components/Search'
import { PriceRangeControl } from '@/components/layout/search/PriceRangeControl.client'
import { FilterList } from '@/components/layout/search/filter'
import { ShopActiveFiltersControl } from '@/components/shop/ShopActiveFiltersControl'
import {
  type ShopFilterGroupConfig,
  type ShopFilterSource,
  ShopFilters,
} from '@/components/layout/search/ShopFilters'
import { sorting } from '@/lib/constants'

export type ShopSidebarLayout = NonNullable<ShopArchiveBlock['sidebarLayout']>

type ShopSidebarControlsProps = {
  facetCounts?: ShopFacetCounts
  filterLabels?: ShopFilterLabels
  filters?: ParsedShopSearchParams
  sidebarEyebrow?: null | string
  sidebarLayout: ShopSidebarLayout
  sidebarTitle?: null | string
}

type LegacySidebarLayoutOptions = {
  showFilters?: boolean | null
  showSort?: boolean | null
}

const legacyFilterSources: ShopFilterSource[] = [
  'segment',
  'category',
  'attribute',
  'usecase',
  'size',
]

function SearchFallback() {
  return (
    <div className="relative w-full">
      <div className="h-12 w-full animate-pulse rounded-2xl border bg-neutral-100 dark:border-neutral-800 dark:bg-neutral-900" />
    </div>
  )
}

export const hasConfiguredSidebarLayout = (
  sidebarLayout?: null | ShopArchiveBlock['sidebarLayout'],
): sidebarLayout is ShopSidebarLayout => {
  return Array.isArray(sidebarLayout) && sidebarLayout.length > 0
}

export const getLegacySidebarLayout = ({
  showFilters = true,
  showSort = true,
}: LegacySidebarLayoutOptions): ShopSidebarLayout => {
  return [
    ...(showFilters !== false
      ? legacyFilterSources.map((source) => ({
          blockType: 'filterGroupControl' as const,
          source,
        }))
      : []),
    ...(showSort !== false
      ? [
          {
            blockType: 'sortControl' as const,
          },
        ]
      : []),
  ]
}

const toFilterGroupConfig = (
  control: Extract<ShopSidebarLayout[number], { blockType: 'filterGroupControl' }>,
): ShopFilterGroupConfig => {
  return {
    attributeGroup: control.attributeGroup,
    displayStyle: control.displayStyle,
    emptyLabel: control.emptyLabel,
    maxVisibleItems: control.maxVisibleItems,
    showCounts: control.showCounts,
    showLessLabel: control.showLessLabel,
    showMoreLabel: control.showMoreLabel,
    source: control.source,
    title: control.title,
    zeroCountBehavior: control.zeroCountBehavior,
  }
}

export function ShopSidebarControls({
  facetCounts,
  filterLabels,
  filters,
  sidebarEyebrow,
  sidebarLayout,
  sidebarTitle,
}: ShopSidebarControlsProps) {
  const controls: ReactNode[] = []
  let pendingFilterGroups: ShopFilterGroupConfig[] = []
  let hasRenderedHeading = false

  const pushHeading = () => {
    if (hasRenderedHeading || (!sidebarEyebrow && !sidebarTitle)) {
      return
    }

    const hasPreviousControl = controls.length > 0

    controls.push(
      <div
        className={hasPreviousControl ? 'border-t border-[#dbe8d7] pt-4' : undefined}
        key="sidebar-heading"
      >
        {sidebarEyebrow ? (
          <p className="text-[10px] font-semibold uppercase tracking-[0.2em] text-[#607668]">
            {sidebarEyebrow}
          </p>
        ) : null}
        {sidebarTitle ? (
          <h2 className="mt-1 text-base font-semibold tracking-tight text-[#063f2b]">
            {sidebarTitle}
          </h2>
        ) : null}
      </div>,
    )
    hasRenderedHeading = true
  }

  const flushFilterGroups = () => {
    if (pendingFilterGroups.length === 0) {
      return
    }

    controls.push(
      <ShopFilters
        facetCounts={facetCounts}
        groups={pendingFilterGroups}
        key={`filter-groups-${controls.length}`}
      />,
    )
    pendingFilterGroups = []
  }

  sidebarLayout.forEach((control, index) => {
    switch (control.blockType) {
      case 'filterGroupControl':
        pushHeading()
        pendingFilterGroups.push(toFilterGroupConfig(control))
        return

      case 'searchControl':
        flushFilterGroups()
        controls.push(
          <Suspense fallback={<SearchFallback />} key={control.id || `search-${index}`}>
            <Search label={control.label} placeholder={control.placeholder} />
          </Suspense>,
        )
        pushHeading()
        return

      case 'sortControl':
        pushHeading()
        flushFilterGroups()
        controls.push(
          <FilterList
            key={control.id || `sort-${index}`}
            list={sorting}
            title={control.title || 'Sort by'}
          />,
        )
        return

      case 'priceRangeControl':
        pushHeading()
        flushFilterGroups()
        controls.push(
          <PriceRangeControl
            applyLabel={control.applyLabel}
            key={control.id || `price-range-${index}`}
            maxPlaceholder={control.maxPlaceholder}
            minPlaceholder={control.minPlaceholder}
            title={control.title}
          />,
        )
        return

      case 'activeFiltersControl':
        pushHeading()
        flushFilterGroups()
        controls.push(
          <ShopActiveFiltersControl
            clearLabel={control.clearLabel}
            emptyLabel={control.emptyLabel}
            filterLabels={filterLabels}
            filters={filters}
            key={control.id || `active-filters-${index}`}
            showWhenEmpty={control.showWhenEmpty}
            title={control.title}
          />,
        )
        return

      case 'dividerControl':
        pushHeading()
        flushFilterGroups()
        controls.push(
          <div
            aria-hidden="true"
            className="border-t border-[#dbe8d7]"
            key={control.id || `divider-${index}`}
          />,
        )
        return

      case 'noteControl':
        pushHeading()
        flushFilterGroups()
        if (control.text) {
          controls.push(
            <p
              className="rounded-2xl border border-[#dbe8d7] bg-white px-4 py-3 text-xs leading-relaxed text-[#607668] shadow-sm"
              key={control.id || `note-${index}`}
            >
              {control.text}
            </p>,
          )
        }
        return
    }
  })

  pushHeading()
  flushFilterGroups()

  if (controls.length === 0) {
    return null
  }

  return <div className="flex flex-col gap-5">{controls}</div>
}
