import { useEffect, useState, type Dispatch, type SetStateAction } from 'react'
import type { Article } from '@/types/nostr'
import { useArticleEditing } from '@/hooks/useArticleEditing'
import { UserArticlesView } from './UserArticlesList'
import { EditPanel } from './UserArticlesEditPanel'

interface UserArticlesProps {
  articles: Article[]
  loading: boolean
  error: string | null
  onLoadContent: (articleId: string, authorPubkey: string) => Promise<Article | null>
  showEmptyMessage?: boolean
  currentPubkey: string | null
  onSelectSeries?: ((seriesId: string | undefined) => void) | undefined
}

export function UserArticles({
  articles,
  loading,
  error,
  onLoadContent,
  showEmptyMessage = true,
  currentPubkey,
  onSelectSeries,
}: UserArticlesProps) {
  const controller = useUserArticlesController({ articles, onLoadContent, currentPubkey })
  return (
    <UserArticlesLayout
      controller={controller}
      loading={loading}
      error={error}
      showEmptyMessage={showEmptyMessage ?? true}
      currentPubkey={currentPubkey}
      onSelectSeries={onSelectSeries}
    />
  )
}

function useUserArticlesController({
  articles,
  onLoadContent,
  currentPubkey,
}: {
  articles: Article[]
  onLoadContent: (articleId: string, authorPubkey: string) => Promise<Article | null>
  currentPubkey: string | null
}) {
  const [localArticles, setLocalArticles] = useState<Article[]>(articles)
  const [unlockedArticles, setUnlockedArticles] = useState<Set<string>>(new Set())
  const [pendingDeleteId, setPendingDeleteId] = useState<string | null>(null)
  const editingCtx = useArticleEditing(currentPubkey)

  useEffect(() => setLocalArticles(articles), [articles])

  return {
    localArticles,
    unlockedArticles,
    pendingDeleteId,
    requestDelete: (id: string) => setPendingDeleteId(id),
    handleUnlock: createHandleUnlock(onLoadContent, setUnlockedArticles),
    handleDelete: createHandleDelete(editingCtx.deleteArticle, setLocalArticles, setPendingDeleteId),
    handleEditSubmit: createHandleEditSubmit(
      editingCtx.submitEdit,
      editingCtx.editingDraft,
      currentPubkey,
      setLocalArticles
    ),
    ...editingCtx,
  }
}

function createHandleUnlock(
  onLoadContent: (id: string, pubkey: string) => Promise<Article | null>,
  setUnlocked: Dispatch<SetStateAction<Set<string>>>
) {
  return async (article: Article) => {
    const full = await onLoadContent(article.id, article.pubkey)
    if (full?.paid) {
      setUnlocked((prev) => new Set([...prev, article.id]))
    }
  }
}

function createHandleDelete(
  deleteArticle: (id: string) => Promise<boolean>,
  setLocalArticles: Dispatch<SetStateAction<Article[]>>,
  setPendingDeleteId: Dispatch<SetStateAction<string | null>>
) {
  return async (article: Article) => {
    const ok = await deleteArticle(article.id)
    if (ok) {
      setLocalArticles((prev) => prev.filter((a) => a.id !== article.id))
    }
    setPendingDeleteId(null)
  }
}

function createHandleEditSubmit(
  submitEdit: () => Promise<import('@/lib/articleMutations').ArticleUpdateResult | null>,
  draft: ReturnType<typeof useArticleEditing>['editingDraft'],
  currentPubkey: string | null,
  setLocalArticles: Dispatch<SetStateAction<Article[]>>
) {
  return async () => {
    const result = await submitEdit()
    if (result && draft) {
      const updated = buildUpdatedArticle(draft, currentPubkey ?? '', result.articleId)
      setLocalArticles((prev) => {
        const filtered = prev.filter((a) => a.id !== result.originalArticleId)
        return [updated, ...filtered]
      })
    }
  }
}

function buildUpdatedArticle(
  draft: NonNullable<ReturnType<typeof useArticleEditing>['editingDraft']>,
  pubkey: string,
  newId: string
): Article {
  return {
    id: newId,
    pubkey,
    title: draft.title,
    preview: draft.preview,
    content: '',
    createdAt: Math.floor(Date.now() / 1000),
    zapAmount: draft.zapAmount,
    paid: false,
    ...(draft.category ? { category: draft.category } : {}),
  }
}

function UserArticlesLayout({
  controller,
  loading,
  error,
  showEmptyMessage,
  currentPubkey,
  onSelectSeries,
}: {
  controller: ReturnType<typeof useUserArticlesController>
  loading: boolean
  error: string | null
  showEmptyMessage: boolean
  currentPubkey: string | null
  onSelectSeries?: ((seriesId: string | undefined) => void) | undefined
}) {
  const { editPanelProps, listProps } = createLayoutProps(controller, {
    loading,
    error,
    showEmptyMessage,
    currentPubkey,
    onSelectSeries,
  })

  return (
    <div className="space-y-4">
      <EditPanel {...editPanelProps} />
      <UserArticlesView {...listProps} />
    </div>
  )
}

function createLayoutProps(
  controller: ReturnType<typeof useUserArticlesController>,
  view: {
    loading: boolean
    error: string | null
    showEmptyMessage: boolean
    currentPubkey: string | null
    onSelectSeries?: ((seriesId: string | undefined) => void) | undefined
  }
) {
  return {
    editPanelProps: buildEditPanelProps(controller),
    listProps: buildListProps(controller, view),
  }
}

function buildEditPanelProps(controller: ReturnType<typeof useUserArticlesController>) {
  return {
    draft: controller.editingDraft,
    editingArticleId: controller.editingArticleId,
    loading: controller.loading,
    error: controller.error,
    onCancel: controller.cancelEditing,
    onDraftChange: controller.updateDraft,
    onSubmit: controller.handleEditSubmit,
  }
}

function buildListProps(
  controller: ReturnType<typeof useUserArticlesController>,
  view: {
    loading: boolean
    error: string | null
    showEmptyMessage: boolean
    currentPubkey: string | null
    onSelectSeries?: ((seriesId: string | undefined) => void) | undefined
  }
) {
  return {
    articles: controller.localArticles,
    loading: view.loading,
    error: view.error,
    showEmptyMessage: view.showEmptyMessage,
    unlockedArticles: controller.unlockedArticles,
    onUnlock: (a: Article) => {
      void controller.handleUnlock(a)
    },
    onEdit: (a: Article) => {
      void controller.startEditing(a)
    },
    onDelete: (a: Article) => {
      void controller.handleDelete(a)
    },
    editingArticleId: controller.editingArticleId,
    currentPubkey: view.currentPubkey,
    pendingDeleteId: controller.pendingDeleteId,
    requestDelete: controller.requestDelete,
    ...(view.onSelectSeries ? { onSelectSeries: view.onSelectSeries } : {}),
  }
}
