import * as React from 'react'
import {createContext, useCallback, useContext, useMemo} from 'react'

import {type Shop} from '@shopify/shop-minis-platform'
import {Star} from 'lucide-react'

import {useShopNavigation} from '../../hooks/navigation/useShopNavigation'
import {cn} from '../../lib/utils'
import {
  type ExtractedBrandTheme,
  extractBrandTheme,
  formatReviewCount,
  getFeaturedImages,
  normalizeRating,
} from '../../utils'
import {isDarkColor} from '../../utils/colors'
import {Image} from '../atoms/image'
import {Touchable} from '../atoms/touchable'

interface MerchantCardContextValue {
  // Core data
  shop: Shop

  // Derived data
  cardTheme: ExtractedBrandTheme

  // UI configuration
  touchable: boolean
  featuredImagesLimit: number

  // Actions
  onClick: () => void
}

const MerchantCardContext = createContext<MerchantCardContextValue | undefined>(
  undefined
)

function useMerchantCardContext() {
  const context = useContext(MerchantCardContext)
  if (!context) {
    throw new Error(
      'useMerchantCardContext must be used within a MerchantCardProvider'
    )
  }
  return context
}

function MerchantCardContainer({
  className,
  ...props
}: React.ComponentProps<'div'>) {
  const {touchable, cardTheme, onClick} = useMerchantCardContext()

  const content = (
    <div
      style={{
        backgroundColor: cardTheme.backgroundColor,
      }}
      className={cn(
        'relative w-full overflow-hidden rounded-xl bg-white flex flex-col border border-gray-200 aspect-square isolate',

        className
      )}
      {...props}
    />
  )

  if (touchable && onClick) {
    return (
      <Touchable
        onClick={onClick}
        whileTap={{opacity: 0.7}}
        transition={{
          opacity: {type: 'tween', duration: 0.08, ease: 'easeInOut'},
        }}
      >
        {content}
      </Touchable>
    )
  }

  return content
}

function MerchantCardImage({
  className,
  src,
  alt,
  thumbhash,
  ...props
}: React.ComponentProps<'img'> & {
  src?: string
  alt?: string
  thumbhash?: string
}) {
  if (!src) {
    return <div className="w-full h-full bg-gray-100" />
  }

  if (thumbhash) {
    return (
      <Image
        data-slot="merchant-card-image"
        src={src}
        alt={alt}
        thumbhash={thumbhash}
        className={cn(className)}
        {...props}
      />
    )
  }

  return (
    <img
      data-slot="merchant-card-image"
      src={src}
      alt={alt}
      className={cn('size-full object-cover', className)}
      {...props}
    />
  )
}

function MerchantCardLogo({className, ...props}: React.ComponentProps<'div'>) {
  const {shop} = useMerchantCardContext()
  const {name, visualTheme} = shop

  const logoAverageColor = visualTheme?.brandSettings?.colors?.logoAverage
  const logoDominantColor = visualTheme?.brandSettings?.colors?.logoDominant
  const logoColor = logoAverageColor || logoDominantColor

  const logoBackgroundClassName = useMemo(
    () => (logoColor && isDarkColor(logoColor) ? 'bg-white' : 'bg-gray-800'),
    [logoColor]
  )

  const logoUrl = visualTheme?.logoImage?.url
  const altText = `${name} logo`

  return (
    <div
      data-slot="merchant-card-logo"
      className={cn(
        'absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-10',
        'w-16 h-16 rounded-xl bg-white border-2 border-white shadow-sm',
        'flex items-center justify-center overflow-hidden',
        logoBackgroundClassName,
        className
      )}
      {...props}
    >
      {logoUrl ? (
        <img
          src={logoUrl}
          alt={altText}
          className="w-full h-full object-cover"
        />
      ) : (
        <div className="w-full h-full bg-gray-200 flex items-center justify-center">
          <span className="text-gray-600 font-semibold text-lg">
            {name?.slice(0, 1)}
          </span>
        </div>
      )}
    </div>
  )
}

function MerchantCardInfo({className, ...props}: React.ComponentProps<'div'>) {
  const {cardTheme} = useMerchantCardContext()

  const isDarkTheme = useMemo(() => {
    return (
      cardTheme.backgroundColor !== 'white' &&
      isDarkColor(cardTheme.backgroundColor)
    )
  }, [cardTheme.backgroundColor])

  const textColor = isDarkTheme ? 'text-primary-foreground' : 'text-foreground'

  return (
    <div
      data-slot="merchant-card-info"
      className={cn(
        'p-3 flex-shrink-0 flex flex-col min-w-0',
        textColor,
        className
      )}
      {...props}
    />
  )
}

function MerchantCardName({
  className,
  children,
  ...props
}: React.ComponentProps<'h3'>) {
  const {shop} = useMerchantCardContext()
  const {name} = shop
  const nameContent = children ?? name

  return (
    <h3
      data-slot="merchant-card-name"
      className={cn('text-sm font-medium truncate', className)}
      {...props}
    >
      {nameContent}
    </h3>
  )
}

function MerchantCardRating({
  className,

  ...props
}: React.ComponentProps<'div'> & {
  rating?: number | null
  reviewCount?: number
}) {
  const {shop} = useMerchantCardContext()

  const {
    reviewAnalytics: {averageRating, reviewCount},
  } = shop

  if (!averageRating || !reviewCount) return null

  return (
    <div
      data-slot="merchant-card-rating"
      className={cn('flex items-center gap-1 text-xs', className)}
      {...props}
    >
      <Star className="h-3 w-3 fill-current" />
      <span className="text-xs">
        {normalizeRating(averageRating)} ({formatReviewCount(reviewCount)})
      </span>
    </div>
  )
}

function MerchantCardDefaultHeader({withLogo = false}: {withLogo?: boolean}) {
  const {shop, cardTheme, featuredImagesLimit} = useMerchantCardContext()
  const {visualTheme} = shop

  const featuredImages = useMemo(
    () => getFeaturedImages(visualTheme, featuredImagesLimit),
    [visualTheme, featuredImagesLimit]
  )

  const numberOfFeaturedImages = featuredImages?.length ?? 0

  const displayDefaultCover = () => {
    if (numberOfFeaturedImages > 0) {
      const heightClass = numberOfFeaturedImages === 2 ? 'h-full' : 'h-1/2'
      return featuredImages?.map((image, index) => (
        <div className={`z-0 w-1/2 ${heightClass}`} key={image.url || index}>
          <MerchantCardImage
            src={image.url}
            alt={image.altText ?? undefined}
            thumbhash={image.thumbhash ?? undefined}
            className="aspect-square"
          />
        </div>
      ))
    } else if (cardTheme.type === 'coverImage') {
      return (
        <MerchantCardImage
          src={cardTheme.coverImageUrl}
          thumbhash={cardTheme.coverImageThumbhash}
        />
      )
    }

    return null
  }

  return (
    <div className="w-full h-full bg-muted relative flex flex-wrap overflow-hidden">
      {withLogo && (
        <div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-10">
          <MerchantCardLogo />
        </div>
      )}

      {displayDefaultCover()}
    </div>
  )
}

function MerchantCardBrandedHeader({withLogo = false}: {withLogo?: boolean}) {
  const {shop, cardTheme} = useMerchantCardContext()
  const wordmarkImage = shop.visualTheme?.brandSettings?.headerTheme?.wordmark

  return (
    <div className="size-full relative">
      {cardTheme.type === 'coverImage' && (
        <>
          <MerchantCardImage
            src={cardTheme.coverImageUrl}
            alt={shop.name}
            thumbhash={cardTheme.coverImageThumbhash ?? undefined}
          />

          <div className="absolute inset-0 z-[1] bg-black/20" />

          <div
            className="absolute bottom-0 z-[1] size-full"
            style={{
              background: `linear-gradient(to top, ${cardTheme.backgroundColor} 0%, ${cardTheme.backgroundColor}00 40%)`,
            }}
          />
        </>
      )}

      {withLogo && (
        <div className="absolute inset-0 z-[1] flex items-center justify-center">
          {wordmarkImage ? (
            <img
              src={wordmarkImage.url}
              alt={wordmarkImage.altText || shop.name}
              className="max-h-16 min-h-10 max-w-28 object-contain"
              data-testid="store-data-wordmark"
            />
          ) : (
            <MerchantCardLogo />
          )}
        </div>
      )}
    </div>
  )
}

interface MerchantCardHeaderProps {
  isDefault?: boolean
  withLogo?: boolean
}

function MerchantCardHeader({
  isDefault,
  withLogo,
  className,
  ...props
}: React.ComponentProps<'div'> & MerchantCardHeaderProps) {
  const {cardTheme} = useMerchantCardContext()

  const isBranded =
    cardTheme.type === 'coverImage' || cardTheme.type === 'brandColor'

  return (
    <div
      className={cn('relative overflow-hidden flex-1 flex-wrap', className)}
      {...props}
    >
      {isBranded && !isDefault ? (
        <MerchantCardBrandedHeader withLogo={withLogo} />
      ) : (
        <MerchantCardDefaultHeader withLogo={withLogo} />
      )}
    </div>
  )
}

/**
 * Use when showcasing merchants as destinations, not just product sources. Automatically adapts to merchant's brand colors, logo placement, and featured product images. Respects merchant brand guidelines while maintaining consistent Shop UI patterns.
 * @publicDocs
 */
export interface MerchantCardProps {
  /** The shop/merchant to display */
  shop: Shop
  /** Whether the card is tappable to navigate to shop (default: true) */
  touchable?: boolean
  /** Maximum number of featured product images to show (default: 4) */
  featuredImagesLimit?: number
  /** Custom content to render inside the card */
  children?: React.ReactNode
}

function MerchantCard({
  shop,
  touchable = true,
  featuredImagesLimit = 4,
  children,
}: MerchantCardProps) {
  const {navigateToShop} = useShopNavigation()

  const {id, visualTheme} = shop

  const handleClick = useCallback(() => {
    if (!touchable) return
    navigateToShop({shopId: id})
  }, [navigateToShop, id, touchable])

  const cardTheme = useMemo(
    () => extractBrandTheme(visualTheme?.brandSettings),
    [visualTheme?.brandSettings]
  )

  const contextValue = useMemo<MerchantCardContextValue>(
    () => ({
      shop,
      cardTheme,
      touchable,
      featuredImagesLimit,
      onClick: handleClick,
    }),
    [shop, cardTheme, touchable, featuredImagesLimit, handleClick]
  )

  return (
    <MerchantCardContext.Provider value={contextValue}>
      {children ?? (
        <MerchantCardContainer>
          <MerchantCardHeader withLogo />
          <MerchantCardInfo>
            <MerchantCardName />
            <MerchantCardRating />
          </MerchantCardInfo>
        </MerchantCardContainer>
      )}
    </MerchantCardContext.Provider>
  )
}

export {
  MerchantCard,
  MerchantCardContainer,
  MerchantCardHeader,
  MerchantCardInfo,
  MerchantCardName,
  MerchantCardRating,
}
