import { useEffect, useState } from 'react'
import { Link, useNavigate, useParams } from 'react-router'
import { ArrowLongLeftIcon, PencilSquareIcon, HeartIcon, ChatBubbleLeftIcon, ArrowTopRightOnSquareIcon } from '@heroicons/react/24/outline'
import { HeartIcon as HeartIconSolid } from '@heroicons/react/24/solid'
import type { AppBskyActorDefs } from '@atproto/api'
import type { OAuthSession } from '@atproto/oauth-client-browser'
import CodeMirrorMarkdownEditor from '~/components/CodeMirrorMarkdownEditor'
import { useAuth } from '~/lib/auth-context'
import { useData } from '~/lib/data-context'
import {
  deletePost,
  getPublicPost,
  getBskyPostThread,
  getBskyViewerLike,
  likeBskyPost,
  unlikeBskyPost,
  replyToBskyPost,
  type BskyReply,
} from '~/lib/api-client'

const CC_LICENSE_URLS: Record<string, string> = {
  'CC BY': 'https://creativecommons.org/licenses/by/4.0/',
  'CC BY-SA': 'https://creativecommons.org/licenses/by-sa/4.0/',
  'CC BY-ND': 'https://creativecommons.org/licenses/by-nd/4.0/',
  'CC BY-NC': 'https://creativecommons.org/licenses/by-nc/4.0/',
  'CC BY-NC-SA': 'https://creativecommons.org/licenses/by-nc-sa/4.0/',
  'CC BY-NC-ND': 'https://creativecommons.org/licenses/by-nc-nd/4.0/',
  'CC0': 'https://creativecommons.org/publicdomain/zero/1.0/',
}
import { resolveDid } from '~/lib/atproto'
import CoverImage from '~/components/CoverImage'
import Avatar from '~/components/Avatar'
import CenteredMessage from '~/components/CenteredMessage'
import Spinner from '~/components/Spinner'
import ConfirmDeleteButton from '~/components/ConfirmDeleteButton'
import { SITE_NAME } from '~/lib/site-config'


export default function Post() {
  const { userId, pubRkey, rkey } = useParams<{ userId: string; pubRkey: string; rkey: string }>()
  const { session } = useAuth()
  const { removePost } = useData()
  const navigate = useNavigate()
  const [title, setTitle] = useState<string | null>(null)
  const [content, setContent] = useState<string | null>(null)
  const [cover, setCover] = useState<{ did: string; cid: string } | null>(null)
  const [ownerDid, setOwnerDid] = useState<string | null>(null)
  const [profile, setProfile] = useState<AppBskyActorDefs.ProfileViewDetailed | null>(null)
  const [publishedAt, setPublishedAt] = useState<string | null>(null)
  const [updatedAt, setUpdatedAt] = useState<string | null>(null)
  const [error, setError] = useState<string | null>(null)
  const [bskyPostRef, setBskyPostRef] = useState<{ uri: string; cid: string } | null>(null)
  const [license, setLicense] = useState<string | null>(null)
  const isOwner = !!session && ownerDid === session.sub

  async function handleDelete() {
    if (!session || !rkey) return
    try {
      await deletePost(session, rkey, bskyPostRef ?? undefined)
      removePost(rkey)
      navigate('/')
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to delete article')
    }
  }

  useEffect(() => {
    if (!userId || !rkey) return
    let cancelled = false

    async function load() {
      try {
        const did = await resolveDid(userId!)

        const [indexData, profileRes] = await Promise.all([
          getPublicPost(did, rkey!),
          fetch(`https://api.bsky.app/xrpc/app.bsky.actor.getProfile?actor=${encodeURIComponent(did)}`),
        ])

        if (indexData === null) throw new Error('Post not found')

        if (cancelled) return

        setTitle(indexData.title)
        setContent(indexData.content ?? '')
        setPublishedAt(indexData.publishedAt)
        setUpdatedAt(indexData.updatedAt ?? null)
        if (indexData.coverImageRef) setCover({ did, cid: indexData.coverImageRef })
        if (indexData.bskyPostRef && indexData.bskyPostRef.uri.split('/')[2] === did) setBskyPostRef(indexData.bskyPostRef)
        if (indexData.license) setLicense(indexData.license)
        setOwnerDid(did)
        document.title = `${indexData.title} — ${SITE_NAME}`
        const atUri = `at://${did}/site.standard.document/${rkey!}`
        let verificationLink = document.head.querySelector<HTMLLinkElement>('link[rel="site.standard.document"]')
        if (!verificationLink) {
          verificationLink = document.createElement('link')
          verificationLink.rel = 'site.standard.document'
          document.head.appendChild(verificationLink)
        }
        verificationLink.href = atUri

        if (indexData.site) {
          let pubLink = document.head.querySelector<HTMLLinkElement>('link[rel="site.standard.publication"]')
          if (!pubLink) {
            pubLink = document.createElement('link')
            pubLink.rel = 'site.standard.publication'
            document.head.appendChild(pubLink)
          }
          pubLink.href = indexData.site
        }

        if (profileRes.ok) {
          const profileData = (await profileRes.json()) as AppBskyActorDefs.ProfileViewDetailed
          if (!cancelled) setProfile(profileData)
        }
      } catch (err) {
        if (!cancelled) setError(err instanceof Error ? err.message : 'Failed to load post')
      }
    }

    load()
    return () => {
      cancelled = true
      document.head.querySelector('link[rel="site.standard.document"]')?.remove()
      document.head.querySelector('link[rel="site.standard.publication"]')?.remove()
    }
  }, [userId, rkey])

  if (error) {
    return <CenteredMessage message={error} error action={{ label: 'Back to profile', to: `/${userId}` }} />
  }

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

  return (
    <div className="flex-1 flex flex-col p-4 md:p-8">
      <div className="w-full max-w-4xl mx-auto space-y-8">

        {/* ── Top bar: back + owner controls ── */}
        <div className="flex items-center justify-between">
          <Link to={`/${profile?.handle ?? userId}`}>
            <ArrowLongLeftIcon className="size-8 text-stone-400 hover:text-stone-700 dark:hover:text-stone-200 transition-colors" />
          </Link>

          {isOwner && (
            <div className="flex items-center gap-3">
              <Link
                to={`/${userId}/pub/${pubRkey}/${rkey}/edit`}
                className="flex items-center gap-1.5 text-sm text-stone-500 dark:text-stone-400 hover:text-stone-700 dark:hover:text-stone-200 transition-colors"
              >
                <PencilSquareIcon className="size-4" />
                Edit
              </Link>
              <ConfirmDeleteButton onDelete={handleDelete} />
            </div>
          )}
        </div>

        {/* ── Title ── */}
        <h1 className="font-display text-3xl md:text-4xl font-semibold text-stone-900 dark:text-white leading-tight">
          {title}
        </h1>

        {/* ── Author byline ── */}
        <div className="flex items-center gap-3">
          <Avatar src={profile?.avatar} size="sm" />
          <div className="min-w-0">
            <p className="text-sm truncate">
              {profile?.displayName && (
                <span className="font-display font-medium text-stone-900 dark:text-white">{profile.displayName}</span>
              )}
              {' '}
              <Link to={`/${profile?.handle ?? userId}`} className="text-stone-500 dark:text-stone-400 hover:text-stone-700 dark:hover:text-stone-200 transition-colors">@{profile?.handle ?? userId}</Link>
            </p>
            {publishedAt && (
              <p className="text-sm text-stone-500 dark:text-stone-400 mt-0.5">
                {updatedAt && updatedAt !== publishedAt ? (
                  <>
                    {'Published '}
                    {new Date(publishedAt).toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' })}
                    {' · Updated '}
                    {new Date(updatedAt).toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' })}
                  </>
                ) : (
                  new Date(publishedAt).toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' })
                )}
              </p>
            )}
          </div>
        </div>

        {/* ── Cover image ── */}
        {cover && (
          <CoverImage
            did={cover.did}
            cid={cover.cid}
            className="max-h-80 w-auto mx-auto block rounded-lg"
          />
        )}

        {/* ── Content ── */}
        <div className="border-t border-stone-100 dark:border-stone-800 pt-8">
          <CodeMirrorMarkdownEditor
            initialValue={content ?? ''}
            displayMode="preview"
            showToolbar={false}
          />
        </div>

        {/* ── License ── */}
        {license && CC_LICENSE_URLS[license] && (
          <p className="text-sm text-stone-500 dark:text-stone-400">
            Licensed under{' '}
            <a
              href={CC_LICENSE_URLS[license]}
              target="_blank"
              rel="noopener noreferrer"
              className="underline hover:text-stone-700 dark:hover:text-stone-200 transition-colors"
            >
              {license}
            </a>
          </p>
        )}

        {/* ── Bluesky engagement ── */}
        {bskyPostRef && (
          <BskyEngagement sidecarRef={bskyPostRef} session={session} />
        )}

      </div>
    </div>
  )
}

const MAX_REPLY_DEPTH = 3

function ReplyNode({ reply, depth }: { reply: BskyReply; depth: number }) {
  return (
    <div>
      <div className="flex gap-3">
        <Avatar src={reply.author.avatar} size="xs" className="mt-0.5" />
        <div className="min-w-0 flex-1">
          <div className="flex items-baseline gap-2 flex-wrap mb-1">
            {reply.author.displayName && (
              <span className="text-sm font-display font-medium text-stone-900 dark:text-white">
                {reply.author.displayName}
              </span>
            )}
            <span className="text-sm text-stone-400 dark:text-stone-500">@{reply.author.handle}</span>
            <span className="text-sm text-stone-400 dark:text-stone-500 ml-auto">
              {new Date(reply.indexedAt).toLocaleDateString(undefined, { month: 'short', day: 'numeric' })}
            </span>
          </div>
          <p className="text-sm text-stone-700 dark:text-stone-300 whitespace-pre-wrap">{reply.text}</p>
        </div>
      </div>

      {depth < MAX_REPLY_DEPTH && reply.replies && reply.replies.length > 0 && (
        <div className="mt-3 ml-4 pl-4 border-l-2 border-stone-100 dark:border-stone-800 space-y-4">
          {reply.replies.map((child) => (
            <ReplyNode key={child.uri} reply={child} depth={depth + 1} />
          ))}
        </div>
      )}
    </div>
  )
}

function BskyEngagement({
  sidecarRef,
  session,
}: {
  sidecarRef: { uri: string; cid: string }
  session: OAuthSession | null
}) {
  const [likeCount, setLikeCount] = useState(0)
  const [replyCount, setReplyCount] = useState(0)
  const [replies, setReplies] = useState<BskyReply[]>([])
  const [likeUri, setLikeUri] = useState<string | null>(null)
  const [liking, setLiking] = useState(false)
  const [showReply, setShowReply] = useState(false)
  const [replyText, setReplyText] = useState('')
  const [replyPending, setReplyPending] = useState(false)
  const [replyError, setReplyError] = useState<string | null>(null)
  const [loaded, setLoaded] = useState(false)
  const [viewerProfile, setViewerProfile] = useState<{ did: string; handle: string; displayName?: string; avatar?: string } | null>(null)

  useEffect(() => {
    let cancelled = false

    async function load() {
      try {
        const data = await getBskyPostThread(sidecarRef.uri)
        if (!cancelled) {
          setLikeCount(data.likeCount)
          setReplyCount(data.replyCount)
          setReplies(data.replies)
          setLoaded(true)
        }
      } catch {
        if (!cancelled) setLoaded(true)
      }

      if (session) {
        const [liked, profileRes] = await Promise.all([
          getBskyViewerLike(session, sidecarRef.uri),
          fetch(`https://api.bsky.app/xrpc/app.bsky.actor.getProfile?actor=${encodeURIComponent(session.sub)}`),
        ])
        if (!cancelled) {
          setLikeUri(liked)
          if (profileRes.ok) {
            const p = await profileRes.json() as { did: string; handle: string; displayName?: string; avatar?: string }
            setViewerProfile(p)
          }
        }
      }
    }

    load()
    return () => { cancelled = true }
  }, [sidecarRef.uri, session])

  async function handleLike() {
    if (!session || liking) return
    setLiking(true)
    try {
      if (likeUri) {
        await unlikeBskyPost(session, likeUri)
        setLikeUri(null)
        setLikeCount((n) => Math.max(0, n - 1))
      } else {
        const newUri = await likeBskyPost(session, sidecarRef)
        setLikeUri(newUri)
        setLikeCount((n) => n + 1)
      }
    } catch {
      // ignore
    } finally {
      setLiking(false)
    }
  }

  async function handleReply(e: React.FormEvent) {
    e.preventDefault()
    if (!session || !replyText.trim() || replyPending) return
    setReplyPending(true)
    setReplyError(null)
    const text = replyText.trim()
    try {
      const { uri } = await replyToBskyPost(session, text, sidecarRef)
      const optimistic: BskyReply = {
        uri,
        author: viewerProfile ?? { did: session.sub, handle: session.sub },
        text,
        indexedAt: new Date().toISOString(),
      }
      setReplies((prev) => [...prev, optimistic])
      setReplyCount((n) => n + 1)
      setReplyText('')
      setShowReply(false)
    } catch (err) {
      setReplyError(err instanceof Error ? err.message : 'Failed to post reply')
    } finally {
      setReplyPending(false)
    }
  }

  const bskyUrl = `https://bsky.app/profile/${sidecarRef.uri.split('/')[2]}/post/${sidecarRef.uri.split('/').at(-1)}`

  return (
    <div className="border-t border-stone-100 dark:border-stone-800 pt-8 space-y-6">

      {/* Stats bar */}
      <div className="flex items-center gap-5">
        <button
          onClick={handleLike}
          disabled={!session || liking}
          aria-label={likeUri ? 'Unlike' : 'Like'}
          title={!session ? 'Sign in to like' : undefined}
          className={`flex items-center gap-2 text-sm font-medium transition-colors ${
            likeUri
              ? 'text-rose-500 dark:text-rose-400'
              : 'text-stone-500 dark:text-stone-400 hover:text-rose-500 dark:hover:text-rose-400 disabled:cursor-default disabled:hover:text-stone-500 dark:disabled:hover:text-stone-400'
          }`}
        >
          {likeUri
            ? <HeartIconSolid className="size-5" />
            : <HeartIcon className="size-5" />
          }
          <span>{loaded ? likeCount : '—'}</span>
        </button>

        <button
          onClick={() => session && setShowReply((s) => !s)}
          disabled={!session}
          aria-label="Reply"
          title={!session ? 'Sign in to reply' : undefined}
          className="flex items-center gap-2 text-sm font-medium text-stone-500 dark:text-stone-400 hover:text-stone-700 dark:hover:text-stone-200 disabled:cursor-default transition-colors"
        >
          <ChatBubbleLeftIcon className="size-5" />
          <span>{loaded ? replyCount : '—'}</span>
        </button>

        <a
          href={bskyUrl}
          target="_blank"
          rel="noopener noreferrer"
          className="ml-auto flex items-center gap-1.5 text-sm text-stone-400 dark:text-stone-500 hover:text-stone-600 dark:hover:text-stone-300 transition-colors"
        >
          View on Bluesky
          <ArrowTopRightOnSquareIcon className="size-3.5" />
        </a>
      </div>

      {/* Reply form */}
      {showReply && (
        <form onSubmit={handleReply} className="space-y-2">
          <textarea
            value={replyText}
            onChange={(e) => setReplyText(e.target.value)}
            placeholder="Write a reply…"
            rows={3}
            maxLength={300}
            autoFocus
            disabled={replyPending}
            className="w-full rounded-lg border border-stone-300 dark:border-stone-600 bg-white dark:bg-stone-800 px-4 py-3 text-sm text-stone-900 dark:text-white placeholder-stone-400 focus:outline-none focus:ring-2 focus:ring-stone-900 dark:focus:ring-stone-100 resize-none disabled:opacity-50"
          />
          <div className="flex items-center justify-between">
            <span className="text-sm text-stone-400 dark:text-stone-500">{replyText.length}/300</span>
            <div className="flex items-center gap-3">
              <button
                type="button"
                onClick={() => { setShowReply(false); setReplyText('') }}
                className="text-sm text-stone-500 dark:text-stone-400 hover:text-stone-700 dark:hover:text-stone-200"
              >
                Cancel
              </button>
              <button
                type="submit"
                disabled={replyPending || !replyText.trim()}
                className="rounded-lg bg-stone-900 dark:bg-stone-100 hover:bg-stone-700 dark:hover:bg-stone-200 disabled:opacity-50 disabled:cursor-not-allowed px-4 py-1.5 text-sm font-semibold text-white dark:text-stone-900 transition-colors"
              >
                {replyPending ? 'Posting…' : 'Reply'}
              </button>
            </div>
          </div>
          {replyError && <p className="text-sm text-red-500">{replyError}</p>}
        </form>
      )}

      {/* Replies */}
      {replies.length > 0 && (
        <div className="space-y-4">
          <p className="text-xs font-semibold tracking-widest uppercase text-stone-400 dark:text-stone-500">
            Responses
          </p>
          <div className="space-y-4">
            {replies.map((reply) => (
              <ReplyNode key={reply.uri} reply={reply} depth={0} />
            ))}
          </div>
        </div>
      )}

    </div>
  )
}
