import { useSecondaryPage } from '@/PageManager'
import { Button } from '@/components/ui/button'
import {
  Carousel,
  CarouselContent,
  CarouselItem,
  CarouselNext,
  CarouselPrevious
} from '@/components/ui/carousel'
import { ExtendedKind } from '@/constants'
import {
  getRelayUrlsWithFavoritesFastReadAndInbox,
  userReadRelaysWithHttp
} from '@/lib/favorites-feed-relays'
import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider'
import { compareEvents } from '@/lib/event'
import { getStarsFromRelayReviewEvent } from '@/lib/event-metadata'
import { toRelayReviews } from '@/lib/link'
import {
  relayReviewDTagsForRelayUrl,
  relayReviewEventTargetsRelay,
  relayReviewsFeedSnapshotKey
} from '@/lib/relay-review-feed'
import { normalizeUrl } from '@/lib/url'
import { cn, isTouchDevice } from '@/lib/utils'
import { useMuteList } from '@/contexts/mute-list-context'
import { muteSetHas } from '@/lib/mute-set'
import { useNostr } from '@/providers/NostrProvider'
import { useUserTrust } from '@/contexts/user-trust-context'
import { queryService } from '@/services/client.service'
import { getSessionFeedSnapshot } from '@/services/session-feed-snapshot.service'
import { WheelGesturesPlugin } from 'embla-carousel-wheel-gestures'
import type { NostrEvent } from 'nostr-tools'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import Stars from '../Stars'
import RelayReviewCard from './RelayReviewCard'
import ReviewEditor from './ReviewEditor'

export default function RelayReviewsPreview({ relayUrl }: { relayUrl: string }) {
  const { t } = useTranslation()
  const { push } = useSecondaryPage()
  const { pubkey, checkLogin, relayList } = useNostr()
  const { favoriteRelays, blockedRelays } = useFavoriteRelays()
  const { hideUntrustedNotes, isUserTrusted } = useUserTrust()
  const { mutePubkeySet } = useMuteList()
  const [showEditor, setShowEditor] = useState(false)
  const [myReview, setMyReview] = useState<NostrEvent | null>(null)
  const [reviews, setReviews] = useState<NostrEvent[]>([])
  const [initialized, setInitialized] = useState(false)
  const { stars, count } = useMemo(() => {
    let totalStars = 0
    let totalCount = 0
    ;[myReview, ...reviews].forEach((evt) => {
      if (!evt) return
      const stars = getStarsFromRelayReviewEvent(evt)
      if (stars) {
        totalStars += stars
        totalCount += 1
      }
    })
    return {
      stars: totalCount > 0 ? +(totalStars / totalCount).toFixed(1) : 0,
      count: totalCount
    }
  }, [myReview, reviews])

  const ingestReviewEvent = useCallback(
    (evt: NostrEvent) => {
      if (muteSetHas(mutePubkeySet, evt.pubkey)) return
      if (hideUntrustedNotes && !isUserTrusted(evt.pubkey)) return
      const stars = getStarsFromRelayReviewEvent(evt)
      if (!stars) return

      if (pubkey && evt.pubkey === pubkey) {
        setMyReview((prev) => (!prev || evt.created_at > prev.created_at ? evt : prev))
        return
      }

      setReviews((prev) => {
        const existing = prev.find((e) => e.pubkey === evt.pubkey)
        if (existing && existing.created_at >= evt.created_at) return prev
        const filtered = prev.filter((e) => e.pubkey !== evt.pubkey)
        return [...filtered, evt].sort((a, b) => compareEvents(b, a))
      })
    },
    [pubkey, mutePubkeySet, hideUntrustedNotes, isUserTrusted]
  )

  useEffect(() => {
    let cancelled = false
    setMyReview(null)
    setReviews([])
    setInitialized(false)

    const normalizedTarget = normalizeUrl(relayUrl) || relayUrl
    const dTags = relayReviewDTagsForRelayUrl(relayUrl)
    const snapKey = relayReviewsFeedSnapshotKey(normalizedTarget)
    const fromSession = getSessionFeedSnapshot(snapKey)
    if (fromSession?.length) {
      let seedMy: NostrEvent | null = null
      const seedByPubkey = new Map<string, NostrEvent>()
      for (const evt of fromSession) {
        if (evt.kind !== ExtendedKind.RELAY_REVIEW || !relayReviewEventTargetsRelay(evt, relayUrl))
          continue
        if (muteSetHas(mutePubkeySet, evt.pubkey)) continue
        if (hideUntrustedNotes && !isUserTrusted(evt.pubkey)) continue
        const st = getStarsFromRelayReviewEvent(evt)
        if (!st) continue
        if (pubkey && evt.pubkey === pubkey) {
          if (!seedMy || evt.created_at > seedMy.created_at) seedMy = evt
        } else {
          const ex = seedByPubkey.get(evt.pubkey)
          if (!ex || evt.created_at > ex.created_at) seedByPubkey.set(evt.pubkey, evt)
        }
      }
      setMyReview(seedMy)
      setReviews([...seedByPubkey.values()].sort((a, b) => compareEvents(b, a)))
    }

    const base = getRelayUrlsWithFavoritesFastReadAndInbox(
      favoriteRelays,
      blockedRelays,
      userReadRelaysWithHttp(relayList)
    )
    const uniqueUrls = [...new Set([normalizedTarget, ...base])]

    const filter = {
      kinds: [ExtendedKind.RELAY_REVIEW],
      '#d': dTags.length > 0 ? dTags : [relayUrl],
      limit: 100
    }

    let dispose: (() => void) | undefined
    let closed = false
    const finish = () => {
      if (closed) return
      closed = true
      if (!cancelled) setInitialized(true)
      dispose?.()
    }

    const sub = queryService.subscribe(uniqueUrls, filter, {
      onevent: (evt) => {
        if (cancelled || evt.kind !== ExtendedKind.RELAY_REVIEW) return
        ingestReviewEvent(evt)
      },
      oneose: () => {
        if (cancelled) return
        finish()
      }
    })
    dispose = sub.close

    const safety = window.setTimeout(() => {
      if (cancelled) return
      finish()
    }, 12_000)

    return () => {
      cancelled = true
      window.clearTimeout(safety)
      finish()
    }
  }, [relayUrl, ingestReviewEvent, favoriteRelays, blockedRelays, relayList])

  const handleReviewed = (evt: NostrEvent) => {
    setMyReview(evt)
    setShowEditor(false)
  }

  return (
    <div className="space-y-4">
      <div className="px-4 flex items-center justify-between">
        <div>
          <div className="flex items-center gap-2">
            <div className="text-lg font-semibold">{stars}</div>
            <Stars stars={stars} />
          </div>
          <div
            className={cn(
              'text-sm text-muted-foreground',
              count > 0 && 'underline cursor-pointer hover:text-foreground'
            )}
            onClick={() => {
              if (count > 0) {
                push(toRelayReviews(relayUrl))
              }
            }}
          >
            {t('{{count}} reviews', { count })}
          </div>
        </div>
        {!showEditor && !myReview && (
          <Button variant="outline" onClick={() => checkLogin(() => setShowEditor(true))}>
            {t('Write a review')}
          </Button>
        )}
      </div>

      {showEditor && <ReviewEditor relayUrl={relayUrl} onReviewed={handleReviewed} />}

      {myReview || reviews.length > 0 ? (
        <ReviewCarousel relayUrl={relayUrl} myReview={myReview} reviews={reviews} />
      ) : !showEditor ? (
        <div className="flex items-center justify-center text-sm text-muted-foreground p-4">
          {initialized ? t('No reviews yet. Be the first to write one!') : t('Loading...')}
        </div>
      ) : null}
    </div>
  )
}

function ReviewCarousel({
  relayUrl,
  myReview,
  reviews
}: {
  relayUrl: string
  myReview: NostrEvent | null
  reviews: NostrEvent[]
}) {
  const { t } = useTranslation()
  const { push } = useSecondaryPage()
  const showPreviousAndNext = useMemo(() => !isTouchDevice(), [])

  return (
    <Carousel
      opts={{
        skipSnaps: true
      }}
      plugins={[WheelGesturesPlugin()]}
    >
      <CarouselContent className="ml-4 mr-2">
        {myReview && (
          <Item key={myReview.id}>
            <RelayReviewCard event={myReview} className="border-primary/60 bg-primary/5" />
          </Item>
        )}
        {reviews.slice(0, 10).map((evt) => (
          <Item key={evt.id}>
            <RelayReviewCard event={evt} />
          </Item>
        ))}
        {reviews.length > 10 && (
          <Item>
            <div
              className="border rounded-lg bg-muted/20 p-3 flex items-center justify-center h-full hover:bg-muted cursor-pointer"
              onClick={() => push(toRelayReviews(relayUrl))}
            >
              <div className="text-sm text-muted-foreground">{t('View more reviews')}</div>
            </div>
          </Item>
        )}
      </CarouselContent>
      {showPreviousAndNext && <CarouselPrevious />}
      {showPreviousAndNext && <CarouselNext />}
    </Carousel>
  )
}

function Item({ children }: { children: React.ReactNode }) {
  return (
    <CarouselItem className="basis-11/12 lg:basis-2/3 2xl:basis-5/12 pl-0 pr-2">
      {children}
    </CarouselItem>
  )
}
