import { z } from "zod"

import {
  contentCardRefSchema,
  contentCardSchema,
  transformContentCard,
} from "./cards/contentCard"
import { buttonSchema } from "./utils/buttonLinkSchema"
import { linkConnectionRefsSchema } from "./utils/linkConnection"

import { BlocksEnums } from "@/types/enums/blocks"

const commonFields = {
  heading: z.string().optional(),
  link: buttonSchema.optional(),
} as const

const carouselCardGroupsFilteredSchema = z
  .array(
    z
      .object({
        filter_identifier: z.string().nullish(),
        filter_label: z.string().nullish(),
        cardConnection: z.object({
          edges: z.array(z.object({ node: contentCardSchema })),
        }),
      })
      .transform((group) => {
        if (!group.filter_label || !group.cardConnection.edges.length) {
          return null
        }
        const iconIdentifier = group.filter_identifier ?? "favorite"
        const identifier = `${group.filter_label.toLowerCase()}-${iconIdentifier}`
        const cards = group.cardConnection.edges
          .map((edge) => transformContentCard(edge.node))
          .filter((card): card is NonNullable<typeof card> => card !== null)
          .map((card) => ({
            ...card,
            filterId: identifier,
          }))
        return {
          label: group.filter_label,
          iconIdentifier,
          identifier,
          cards,
        }
      })
  )
  .transform((groups) =>
    groups.filter((group): group is NonNullable<typeof group> => group !== null)
  )

const carouselCardGroupsNoFilterSchema = z
  .array(
    z
      .object({
        cardConnection: z.object({
          edges: z.array(z.object({ node: contentCardSchema })),
        }),
      })
      .transform((group) => {
        if (!group.cardConnection.edges.length) {
          return null
        }
        const cards = group.cardConnection.edges
          .map((edge) => transformContentCard(edge.node))
          .filter((card): card is NonNullable<typeof card> => card !== null)
          .map((card) => ({
            ...card,
          }))
        return {
          cards,
        }
      })
  )
  .transform((groups) =>
    groups.filter((group): group is NonNullable<typeof group> => group !== null)
  )

const carouselCardsWithFilters = z.object({
  ...commonFields,
  enable_filters: z.literal(true),
  card_groups: carouselCardGroupsFilteredSchema,
})

const carouselCardsWithoutFilters = z.object({
  ...commonFields,
  enable_filters: z.literal(false),
  card_groups: carouselCardGroupsNoFilterSchema,
})

export const carouselCardsSchema = z.object({
  typename: z
    .literal(BlocksEnums.block.CarouselCards)
    .optional()
    .default(BlocksEnums.block.CarouselCards),
  carousel_cards: z
    .discriminatedUnion("enable_filters", [
      carouselCardsWithFilters,
      carouselCardsWithoutFilters,
    ])
    .transform((data) => {
      if (!data.enable_filters) {
        return {
          heading: data.heading,
          enableFilters: false,
          filterCategories: [],
          cards: data.card_groups.map((group) => group.cards).flat(),
          link:
            data.link?.href && data.link.title
              ? { href: data.link.href, text: data.link.title }
              : undefined,
        }
      }

      const filterCategories = data.card_groups.map((group) => ({
        identifier: group.identifier,
        iconIdentifier: group.iconIdentifier,
        label: group.label,
      }))

      return {
        heading: data.heading,
        enableFilters: true,
        filterCategories,
        cards: data.card_groups.map((group) => group.cards).flat(),
        defaultFilter: filterCategories[0]?.identifier,
        link:
          data.link?.href && data.link.title
            ? { href: data.link.href, text: data.link.title }
            : undefined,
      }
    }),
})

export const carouselCardsRefsSchema = z.object({
  typename: z
    .literal(BlocksEnums.block.CarouselCards)
    .optional()
    .default(BlocksEnums.block.CarouselCards),
  carousel_cards: z.object({
    card_groups: z.array(
      z.object({
        cardConnection: z.object({
          edges: z.array(
            z.object({
              node: contentCardRefSchema,
            })
          ),
        }),
      })
    ),
    link: linkConnectionRefsSchema.optional(),
  }),
})
