import { useEffect, useState } from 'react'
import { useParams } from 'react-router'
import type { AppBskyActorDefs } from '@atproto/api'
import {
  listPublicPublications, listPublicPosts,
  listSubscriptions, subscribe, unsubscribe,
  type Post, type Publication,
} from '~/lib/api-client'
import { useAuth } from '~/lib/auth-context'
import ProfileHeader from '~/components/ProfileHeader'
import PostList from '~/components/PostList'
import CenteredMessage from '~/components/CenteredMessage'
import PageLayout from '~/components/PageLayout'
import Spinner from '~/components/Spinner'
import PublicationCard from '~/components/PublicationCard'
import type { Route } from './+types/profile'
import { SITE_NAME } from '~/lib/site-config'

export function meta({ params }: Route.MetaArgs) {
  return [{ title: `${params.userId} — ${SITE_NAME}` }]
}

export default function Profile() {
  const { userId: id } = useParams<{ userId: string }>()
  const { session } = useAuth()
  const [profile, setProfile] = useState<AppBskyActorDefs.ProfileViewDetailed | null>(null)
  const [publications, setPublications] = useState<Publication[] | null>(null)
  const [posts, setPosts] = useState<Post[] | null>(null)
  const [error, setError] = useState<string | null>(null)
  const [postsError, setPostsError] = useState<string | null>(null)
  // publicationAtUri → subscriptionRkey; undefined = not yet loaded
  const [subscriptionsByPub, setSubscriptionsByPub] = useState<Record<string, string> | undefined>(undefined)
  const [loadingPubs, setLoadingPubs] = useState<Record<string, boolean>>({})


  useEffect(() => {
    if (!id) return
    setProfile(null)
    setPublications(null)
    setPosts(null)
    setError(null)
    setPostsError(null)
    setSubscriptionsByPub(undefined)

    let cancelled = false

    async function load() {
      const actor = id!.startsWith('@') ? id!.slice(1) : id!

      try {
        const res = await fetch(
          `https://api.bsky.app/xrpc/app.bsky.actor.getProfile?actor=${encodeURIComponent(actor)}`,
        )
        if (!res.ok) throw new Error(res.status === 400 ? 'Profile not found' : `Failed to load profile (${res.status})`)
        const profileData = (await res.json()) as AppBskyActorDefs.ProfileViewDetailed
        if (cancelled) return
        setProfile(profileData)

        const { did } = profileData

        const fetchPubs = async () => {
          try {
            const pubs = await listPublicPublications(did)
            if (!cancelled) setPublications(pubs)
          } catch {
            if (!cancelled) setPublications([])
          }
        }

        const fetchPosts = async () => {
          try {
            const postList = await listPublicPosts(did)
            if (!cancelled) setPosts(postList)
          } catch {
            if (!cancelled) setPostsError('Failed to load posts')
          }
        }

        const fetchSubs = session && session.sub !== did
          ? listSubscriptions(session)
              .then((subs) => {
                if (cancelled) return
                const byPub: Record<string, string> = {}
                for (const s of subs) byPub[s.publicationAtUri] = s.rkey
                setSubscriptionsByPub(byPub)
              })
              .catch(() => { if (!cancelled) setSubscriptionsByPub({}) })
          : Promise.resolve()

        await Promise.all([fetchPubs(), fetchPosts(), fetchSubs])
      } catch (err) {
        if (!cancelled) setError(err instanceof Error ? err.message : 'Failed to load profile')
      }
    }

    load()
    return () => { cancelled = true }
  }, [id, session])

  async function handleSubscribe(pub: Publication) {
    if (!session) return
    setLoadingPubs((prev) => ({ ...prev, [pub.atUri]: true }))
    try {
      const rkey = await subscribe(session, pub.atUri)
      setSubscriptionsByPub((prev) => ({ ...prev, [pub.atUri]: rkey }))
    } catch {
      // non-fatal
    } finally {
      setLoadingPubs((prev) => ({ ...prev, [pub.atUri]: false }))
    }
  }

  async function handleUnsubscribe(pub: Publication) {
    if (!session || !subscriptionsByPub) return
    const rkey = subscriptionsByPub[pub.atUri]
    if (!rkey) return
    setLoadingPubs((prev) => ({ ...prev, [pub.atUri]: true }))
    try {
      await unsubscribe(session, rkey)
      setSubscriptionsByPub((prev) => {
        const next = { ...prev }
        delete next[pub.atUri]
        return next
      })
    } catch {
      // non-fatal
    } finally {
      setLoadingPubs((prev) => ({ ...prev, [pub.atUri]: false }))
    }
  }

  if (error) {
    return <CenteredMessage message={error} error action={{ label: 'Go home', to: '/' }} />
  }

  if (!profile) {
    return (
      <div className="flex-1 flex items-center justify-center">
        <Spinner />
      </div>
    )
  }

  const isOwnProfile = session?.sub === profile.did
  const showSubscribeButtons = !isOwnProfile && subscriptionsByPub !== undefined

  return (
    <PageLayout spacing="8">
        <ProfileHeader profile={profile} />

        {publications !== null && publications.length > 0 && (
          <div className="space-y-3">
            <h2 className="text-[10px] font-bold uppercase tracking-widest text-stone-400 dark:text-stone-600">
              Publications
            </h2>
            <ul className="space-y-2">
              {publications.map((pub) => {
                const isSubscribed = !!subscriptionsByPub?.[pub.atUri]
                const isLoading = !!loadingPubs[pub.atUri]
                return (
                  <PublicationCard
                    key={pub.atUri}
                    pub={pub}
                    action={showSubscribeButtons && (
                      isSubscribed ? (
                        <button
                          onClick={() => handleUnsubscribe(pub)}
                          disabled={isLoading}
                          className="text-sm px-3 py-1 rounded-full border border-stone-300 dark:border-stone-600 text-stone-600 dark:text-stone-300 hover:border-stone-400 dark:hover:border-stone-500 hover:bg-stone-50 dark:hover:bg-stone-800/50 transition-colors disabled:opacity-50"
                        >
                          {isLoading ? 'Unsubscribing…' : 'Subscribed'}
                        </button>
                      ) : (
                        <button
                          onClick={() => handleSubscribe(pub)}
                          disabled={isLoading}
                          className="text-sm px-3 py-1 rounded-full bg-stone-900 dark:bg-stone-100 text-stone-50 dark:text-stone-900 hover:bg-stone-700 dark:hover:bg-stone-200 transition-colors disabled:opacity-50"
                        >
                          {isLoading ? 'Subscribing…' : 'Subscribe'}
                        </button>
                      )
                    )}
                  />
                )
              })}
            </ul>
          </div>
        )}

        <div className="space-y-5">
          {posts === null ? (
            <h2 className="font-display text-xl font-semibold text-stone-900 dark:text-white">Articles</h2>
          ) : posts.length === 0 ? (
            <h2 className="font-display text-xl font-semibold text-stone-400 dark:text-stone-600">No articles yet</h2>
          ) : (
            <div className="flex items-baseline gap-2.5">
              <span className="font-display text-4xl font-bold text-stone-900 dark:text-white tabular-nums leading-none">
                {posts.length}
              </span>
              <span className="text-[10px] font-bold uppercase tracking-widest text-stone-400 dark:text-stone-600">
                {posts.length === 1 ? 'article' : 'articles'}
              </span>
            </div>
          )}
          <PostList posts={posts} handle={profile.handle} error={postsError} />
        </div>
    </PageLayout>
  )
}
