import { useEffect, useRef, useState } from 'react'
import { Link, useNavigate, useLocation } from 'react-router'
import { useAuth } from '~/lib/auth-context'
import { useData, usePublications } from '~/lib/data-context'
import { createPost, uploadBlob, uploadContentImages, type AtpBlob, type Publication, CC_LICENSES } from '~/lib/api-client'
import { compressImage } from '~/lib/compress-image'
import type { Route } from './+types/publish'
import CodeMirrorMarkdownEditor from '~/components/CodeMirrorMarkdownEditor';
import CoverImagePicker from '~/components/CoverImagePicker'
import { ArrowLongLeftIcon, ArrowTopRightOnSquareIcon } from '@heroicons/react/24/outline'
import CenteredMessage from '~/components/CenteredMessage'
import Spinner from '~/components/Spinner'
import { SITE_NAME } from '~/lib/site-config'

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

export default function Publish() {
  const { session, loading } = useAuth()
  const navigate = useNavigate()

  useEffect(() => {
    if (!loading && !session) navigate('/')
  }, [loading, session, navigate])

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

  return <PublishScreen session={session} />
}

function PublishScreen({ session }: { session: NonNullable<ReturnType<typeof useAuth>['session']> }) {
  const navigate = useNavigate()
  const location = useLocation()
  const publications = usePublications()
  const { invalidatePosts } = useData()
  const [selectedPubAtUri, setSelectedPubAtUri] = useState<string | null>(
    () => (location.state as { publication?: Publication } | null)?.publication?.atUri ?? null,
  )
  const [title, setTitle] = useState('')
  const [visibility, setVisibility] = useState<'published' | 'draft'>('published')
  const [pending, setPending] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const [draftSaved, setDraftSaved] = useState(false)
  const [postRkey, setPostRkey] = useState<string | null>(null)
  const [markdownValue, setMarkdownValue] = useState(''); // props.initialValue || ''
  const [coverImageBlob, setCoverImageBlob] = useState<AtpBlob | null>(null)
  const [coverImagePreviewUrl, setCoverImagePreviewUrl] = useState<string | null>(null)
  const [coverImageUploading, setCoverImageUploading] = useState(false)
  const [coverImageError, setCoverImageError] = useState<string | null>(null)
  const coverPreviewUrlRef = useRef<string | null>(null)
  const [bskyPostText, setBskyPostText] = useState('')
  const [license, setLicense] = useState('')

  useEffect(() => {
    if (publications) setSelectedPubAtUri((prev) => prev ?? publications[0]?.atUri ?? null)
  }, [publications])

  const publication = publications?.find((p) => p.atUri === selectedPubAtUri) ?? null

  // Simple onChange handler for CodeMirror editor
  const handleContentChange = (value: string) => {
    setMarkdownValue(value);
  };

  async function handleCoverImageSelect(file: File) {
    setCoverImageError(null)
    setCoverImageUploading(true)
    try {
      const compressed = await compressImage(file)
      const localUrl = URL.createObjectURL(compressed)
      if (coverPreviewUrlRef.current) URL.revokeObjectURL(coverPreviewUrlRef.current)
      coverPreviewUrlRef.current = localUrl
      setCoverImagePreviewUrl(localUrl)
      const blob = await uploadBlob(session, compressed)
      setCoverImageBlob(blob)
    } catch (err) {
      setCoverImageError(err instanceof Error ? err.message : 'Upload failed')
      setCoverImageBlob(null)
    } finally {
      setCoverImageUploading(false)
    }
  }

  function handleCoverImageRemove() {
    if (coverPreviewUrlRef.current) {
      URL.revokeObjectURL(coverPreviewUrlRef.current)
      coverPreviewUrlRef.current = null
    }
    setCoverImagePreviewUrl(null)
    setCoverImageBlob(null)
    setCoverImageError(null)
  }

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault()
    if (!publication || !title.trim()) return
    setPending(true)
    setError(null)
    setDraftSaved(false)
    try {
      const { content: finalContent, imageBlobs } = await uploadContentImages(session, markdownValue)
      const post = await createPost(
        session,
        publication.atUri,
        title.trim(),
        finalContent,
        visibility,
        postRkey ?? undefined,
        coverImageBlob ?? undefined,
        visibility === 'published'
          ? { text: bskyPostText.trim(), pubUrl: publication.url }
          : undefined,
        imageBlobs.length > 0 ? imageBlobs : undefined,
        license || undefined,
      )
      invalidatePosts()
      if (visibility === 'published') {
        navigate('/')
      } else {
        setPostRkey(post.atUri.split('/').pop()!)
        setDraftSaved(true)
        setPending(false)
      }
    } catch (err) {
      setError(err instanceof Error ? err.message : visibility === 'published' ? 'Failed to publish' : 'Failed to save draft')
      setPending(false)
    }
  }

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

  if (!publication) {
    return <CenteredMessage message="Create a publication before publishing articles." action={{ label: 'Go back', to: '/' }} />
  }

  return (
    <div className="flex-1 flex flex-col p-4 md:p-8">
      <div className="w-full max-w-sm mx-auto md:max-w-none space-y-6">
        <div className="flex items-center justify-between">
          <div className="flex items-center gap-3">
            <Link to="/">
              <ArrowLongLeftIcon className="size-9" />
            </Link>
            <h1 className="font-display text-xl font-semibold text-stone-900 dark:text-white">New article</h1>
          </div>

          {publications.length > 1 ? (
            <select
              value={selectedPubAtUri ?? ''}
              onChange={(e) => setSelectedPubAtUri(e.target.value)}
              disabled={pending}
              className="rounded-lg border border-stone-200 dark:border-stone-700 bg-white dark:bg-stone-800 px-3 py-2 text-sm text-stone-700 dark:text-stone-300 focus:outline-none focus:ring-2 focus:ring-stone-900 dark:focus:ring-stone-100 disabled:opacity-50"
            >
              {publications.map((pub) => (
                <option key={pub.sk} value={pub.atUri}>
                  {pub.name} — {new URL(pub.url).host}
                </option>
              ))}
            </select>
          ) : (
            <div className="rounded-lg border border-stone-200 dark:border-stone-700 px-3 py-2">
              <p className="text-sm text-stone-500 dark:text-stone-400">
                Publishing to{' '}
                <span className="font-medium text-stone-900 dark:text-white">{publication.name}</span>
              </p>
            </div>
          )}
        </div>

        <form onSubmit={handleSubmit} className="space-y-3">
          <div className="flex gap-3 flex-wrap">
            <input
              type="text"
              value={title}
              onChange={(e) => setTitle(e.target.value)}
              placeholder="Title"
              autoFocus
              disabled={pending}
              className="flex-1 min-w-0 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 disabled:opacity-50"
            />
            <div className="flex rounded-lg border border-stone-300 dark:border-stone-600 overflow-hidden text-sm font-medium">
              {(['draft', 'published'] as const).map((v) => (
                <button
                  key={v}
                  type="button"
                  disabled={pending}
                  onClick={() => setVisibility(v)}
                  className={
                    visibility === v
                      ? 'px-4 py-3 bg-stone-900 dark:bg-stone-100 text-white dark:text-stone-900 transition-colors'
                      : 'px-4 py-3 bg-white dark:bg-stone-800 text-stone-500 dark:text-stone-400 hover:bg-stone-50 dark:hover:bg-stone-700 transition-colors disabled:opacity-50'
                  }
                >
                  {v.charAt(0).toUpperCase() + v.slice(1)}
                </button>
              ))}
            </div>
            <button
              type="submit"
              disabled={pending || !title.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-6 py-3 text-sm font-semibold text-white dark:text-stone-900 transition-colors whitespace-nowrap"
            >
              {pending
                ? visibility === 'published' ? 'Publishing…' : 'Saving…'
                : visibility === 'published' ? 'Publish' : 'Save Draft'}
            </button>
          </div>

          {error && <p className="text-sm text-red-500">{error}</p>}
          {draftSaved && <p className="text-sm text-green-600 dark:text-green-400">Draft saved.</p>}

          <CoverImagePicker
            previewUrl={coverImagePreviewUrl}
            uploading={coverImageUploading}
            error={coverImageError}
            onSelect={handleCoverImageSelect}
            onRemove={handleCoverImageRemove}
          />

          <div className="space-y-1.5">
            <label className="text-sm font-medium text-stone-500 dark:text-stone-400">
              License <span className="font-normal text-stone-400 dark:text-stone-500">(optional)</span>
              {' · '}
              <a href="https://creativecommons.org/cc-licenses/" target="_blank" rel="noopener noreferrer" className="font-normal underline underline-offset-2 hover:text-stone-700 dark:hover:text-stone-200 transition-colors">
                about CC licenses <ArrowTopRightOnSquareIcon className="inline-block w-4 h-4 mb-0.5" />
              </a>
            </label>
            <select
              value={license}
              onChange={(e) => setLicense(e.target.value)}
              disabled={pending}
              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 focus:outline-none focus:ring-2 focus:ring-stone-900 dark:focus:ring-stone-100 disabled:opacity-50"
            >
              <option value="">No license specified</option>
              {CC_LICENSES.map((l) => (
                <option key={l} value={l}>{l}</option>
              ))}
            </select>
          </div>

          {visibility === 'published' && (
            <div className="space-y-1.5">
              <label className="text-sm font-medium text-stone-500 dark:text-stone-400">
                Bluesky post{' '}
                <span className="font-normal text-stone-400 dark:text-stone-500">(a Bluesky post links Comments and Likes across platforms)</span>
              </label>
              <textarea
                value={bskyPostText}
                onChange={(e) => setBskyPostText(e.target.value)}
                placeholder="Add text to your Bluesky post… (optional)"
                rows={3}
                maxLength={300}
                disabled={pending}
                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 disabled:opacity-50 resize-none"
              />
              <p className="text-sm text-stone-400 dark:text-stone-500 text-right">{bskyPostText.length}/300</p>
            </div>
          )}

          <CodeMirrorMarkdownEditor
            initialValue={''}
            onChange={handleContentChange}
            displayMode="split"
            showToolbar={true}
          />
        </form>
      </div>
    </div>
  )
}
