import { useState } from 'react'
import type { MediaRef, Page } from '@/types/nostr'
import { uploadNip95Media } from '@/lib/nip95'
import { t } from '@/lib/i18n'

interface MarkdownEditorTwoColumnsProps {
  value: string
  onChange: (value: string) => void
  pages?: Page[]
  onPagesChange?: (pages: Page[]) => void
  onMediaAdd?: (media: MediaRef) => void
  onBannerChange?: (url: string) => void
}

export function MarkdownEditorTwoColumns({
  value,
  onChange,
  pages = [],
  onPagesChange,
  onMediaAdd,
  onBannerChange,
}: MarkdownEditorTwoColumnsProps): React.ReactElement {
  const [uploading, setUploading] = useState(false)
  const [error, setError] = useState<string | null>(null)

  const pagesHandlers = createPagesHandlers({ pages, onPagesChange })
  const handleImageUpload = createImageUploadHandler({
    setError,
    setUploading,
    onMediaAdd,
    onBannerChange,
    onSetPageImageUrl: pagesHandlers.setPageContent,
  })

  return (
    <div className="space-y-4">
      <MarkdownToolbar
        onFileSelected={(file) => {
          void handleImageUpload({ file })
        }}
        uploading={uploading}
        error={error}
        {...(onPagesChange ? { onAddPage: pagesHandlers.addPage } : {})}
      />
      <div className="grid grid-cols-2 gap-4">
        <EditorColumn value={value} onChange={onChange} />
        <PreviewColumn value={value} />
      </div>
      {onPagesChange && (
        <PagesManager
          pages={pages}
          onPageContentChange={pagesHandlers.setPageContent}
          onPageTypeChange={pagesHandlers.setPageType}
          onRemovePage={pagesHandlers.removePage}
          onImageUpload={async (file, pageNumber) => {
            await handleImageUpload({ file, pageNumber })
          }}
        />
      )}
    </div>
  )
}

function MarkdownToolbar({
  onFileSelected,
  uploading,
  error,
  onAddPage,
}: {
  onFileSelected: (file: File) => void
  uploading: boolean
  error: string | null
  onAddPage?: (type: 'markdown' | 'image') => void
}): React.ReactElement {
  return (
    <div className="flex items-center gap-2 flex-wrap">
      <ToolbarUploadButton onFileSelected={onFileSelected} />
      <ToolbarAddPageButtons onAddPage={onAddPage} />
      <ToolbarStatus uploading={uploading} error={error} />
    </div>
  )
}

function MarkdownPreview({ value }: { value: string }): React.ReactElement {
  return (
    <div className="prose max-w-none border rounded p-3 bg-white h-96 overflow-y-auto whitespace-pre-wrap">
      {value || <span className="text-gray-400">{t('markdown.preview.empty')}</span>}
    </div>
  )
}

function PagesManager({
  pages,
  onPageContentChange,
  onPageTypeChange,
  onRemovePage,
  onImageUpload,
}: {
  pages: Page[]
  onPageContentChange: (pageNumber: number, content: string) => void
  onPageTypeChange: (pageNumber: number, type: 'markdown' | 'image') => void
  onRemovePage: (pageNumber: number) => void
  onImageUpload: (file: File, pageNumber: number) => Promise<void>
}): React.ReactElement {
  if (pages.length === 0) {
    return <div className="text-sm text-gray-500">{t('page.empty')}</div>
  }

  return (
    <div className="space-y-4">
      <h3 className="text-lg font-semibold">{t('page.title')}</h3>
      {pages.map((page) => (
        <PageEditor
          key={page.number}
          page={page}
          onContentChange={(content) => onPageContentChange(page.number, content)}
          onTypeChange={(type) => onPageTypeChange(page.number, type)}
          onRemove={() => onRemovePage(page.number)}
          onImageUpload={async (file) => {
            await onImageUpload(file, page.number)
          }}
        />
      ))}
    </div>
  )
}

function PageEditor({
  page,
  onContentChange,
  onTypeChange,
  onRemove,
  onImageUpload,
}: {
  page: Page
  onContentChange: (content: string) => void
  onTypeChange: (type: 'markdown' | 'image') => void
  onRemove: () => void
  onImageUpload: (file: File) => Promise<void>
}): React.ReactElement {
  return (
    <div className="border rounded-lg p-4 space-y-3">
      <PageEditorHeader page={page} onTypeChange={onTypeChange} onRemove={onRemove} />
      <PageEditorBody page={page} onContentChange={onContentChange} onImageUpload={onImageUpload} />
    </div>
  )
}

function EditorColumn(params: { value: string; onChange: (value: string) => void }): React.ReactElement {
  return (
    <div className="space-y-2">
      <label className="block text-sm font-semibold text-gray-800">{t('markdown.editor')}</label>
      <textarea
        className="w-full border rounded p-3 h-96 font-mono text-sm"
        value={params.value}
        onChange={(e) => params.onChange(e.target.value)}
        placeholder={t('markdown.placeholder')}
      />
    </div>
  )
}

function PreviewColumn(params: { value: string }): React.ReactElement {
  return (
    <div className="space-y-2">
      <label className="block text-sm font-semibold text-gray-800">{t('markdown.preview')}</label>
      <MarkdownPreview value={params.value} />
    </div>
  )
}

function ToolbarUploadButton(params: { onFileSelected: (file: File) => void }): React.ReactElement {
  return (
    <label className="px-3 py-1 text-sm rounded bg-blue-600 text-white cursor-pointer hover:bg-blue-700">
      {t('markdown.upload.media')}
      <input
        type="file"
        accept=".png,.jpg,.jpeg,.webp"
        className="hidden"
        onChange={(e) => {
          const file = e.target.files?.[0]
          if (file) {
            params.onFileSelected(file)
          }
        }}
      />
    </label>
  )
}

function ToolbarAddPageButtons(params: { onAddPage: ((type: 'markdown' | 'image') => void) | undefined }): React.ReactElement | null {
  if (!params.onAddPage) {
    return null
  }
  return (
    <>
      <button
        type="button"
        className="px-3 py-1 text-sm rounded bg-green-600 text-white hover:bg-green-700"
        onClick={() => params.onAddPage?.('markdown')}
      >
        {t('page.add.markdown')}
      </button>
      <button
        type="button"
        className="px-3 py-1 text-sm rounded bg-purple-600 text-white hover:bg-purple-700"
        onClick={() => params.onAddPage?.('image')}
      >
        {t('page.add.image')}
      </button>
    </>
  )
}

function ToolbarStatus(params: { uploading: boolean; error: string | null }): React.ReactElement | null {
  if (!params.uploading && !params.error) {
    return null
  }
  return (
    <>
      {params.uploading ? <span className="text-sm text-gray-500">{t('markdown.upload.uploading')}</span> : null}
      {params.error ? <span className="text-sm text-red-600">{params.error}</span> : null}
    </>
  )
}

function PageEditorHeader(params: {
  page: Page
  onTypeChange: (type: 'markdown' | 'image') => void
  onRemove: () => void
}): React.ReactElement {
  return (
    <div className="flex items-center justify-between">
      <h4 className="font-semibold">
        {t('page.number', { number: params.page.number })} - {t(`page.type.${params.page.type}`)}
      </h4>
      <div className="flex items-center gap-2">
        <select
          value={params.page.type}
          onChange={(e) => params.onTypeChange(e.target.value as 'markdown' | 'image')}
          className="text-sm border rounded px-2 py-1"
        >
          <option value="markdown">{t('page.type.markdown')}</option>
          <option value="image">{t('page.type.image')}</option>
        </select>
        <button
          type="button"
          className="px-2 py-1 text-sm rounded bg-red-600 text-white hover:bg-red-700"
          onClick={params.onRemove}
        >
          {t('page.remove')}
        </button>
      </div>
    </div>
  )
}

function PageEditorBody(params: {
  page: Page
  onContentChange: (content: string) => void
  onImageUpload: (file: File) => Promise<void>
}): React.ReactElement {
  if (params.page.type === 'markdown') {
    return (
      <textarea
        className="w-full border rounded p-2 h-48 font-mono text-sm"
        value={params.page.content}
        onChange={(e) => params.onContentChange(e.target.value)}
        placeholder={t('page.markdown.placeholder')}
      />
    )
  }

  return <PageEditorImageBody page={params.page} onContentChange={params.onContentChange} onImageUpload={params.onImageUpload} />
}

function PageEditorImageBody(params: {
  page: Page
  onContentChange: (content: string) => void
  onImageUpload: (file: File) => Promise<void>
}): React.ReactElement {
  return (
    <div className="space-y-2">
      {params.page.content ? (
        <div className="relative">
          <img src={params.page.content} alt={t('page.image.alt', { number: params.page.number })} className="max-w-full h-auto rounded" />
          <button
            type="button"
            className="absolute top-2 right-2 px-2 py-1 text-sm rounded bg-red-600 text-white hover:bg-red-700"
            onClick={() => params.onContentChange('')}
          >
            {t('page.image.remove')}
          </button>
        </div>
      ) : (
        <PageImageUploadButton onFileSelected={params.onImageUpload} />
      )}
    </div>
  )
}

function PageImageUploadButton(params: { onFileSelected: (file: File) => Promise<void> }): React.ReactElement {
  return (
    <label className="block px-3 py-2 text-sm rounded bg-blue-600 text-white cursor-pointer hover:bg-blue-700 text-center">
      {t('page.image.upload')}
      <input
        type="file"
        accept=".png,.jpg,.jpeg,.webp"
        className="hidden"
        onChange={(e) => {
          const file = e.target.files?.[0]
          if (file) {
            void params.onFileSelected(file)
          }
        }}
      />
    </label>
  )
}

function createPagesHandlers(params: {
  pages: Page[]
  onPagesChange: ((pages: Page[]) => void) | undefined
}): { addPage: (type: 'markdown' | 'image') => void; setPageContent: (pageNumber: number, content: string) => void; setPageType: (pageNumber: number, type: 'markdown' | 'image') => void; removePage: (pageNumber: number) => void } {
  const update = (next: Page[]): void => {
    params.onPagesChange?.(next)
  }

  return {
    addPage: (type) => {
      if (!params.onPagesChange) {
        return
      }
      const newPage: Page = { number: params.pages.length + 1, type, content: '' }
      update([...params.pages, newPage])
    },
    setPageContent: (pageNumber, content) => {
      if (!params.onPagesChange) {
        return
      }
      update(params.pages.map((p) => (p.number === pageNumber ? { ...p, content } : p)))
    },
    setPageType: (pageNumber, type) => {
      if (!params.onPagesChange) {
        return
      }
      update(params.pages.map((p) => (p.number === pageNumber ? { ...p, type, content: '' } : p)))
    },
    removePage: (pageNumber) => {
      if (!params.onPagesChange) {
        return
      }
      update(params.pages.filter((p) => p.number !== pageNumber).map((p, idx) => ({ ...p, number: idx + 1 })))
    },
  }
}

function createImageUploadHandler(params: {
  setError: (value: string | null) => void
  setUploading: (value: boolean) => void
  onMediaAdd: ((media: MediaRef) => void) | undefined
  onBannerChange: ((url: string) => void) | undefined
  onSetPageImageUrl: (pageNumber: number, url: string) => void
}): (args: { file: File; pageNumber?: number }) => Promise<void> {
  return async (args): Promise<void> => {
    params.setError(null)
    params.setUploading(true)
    try {
      const media = await uploadNip95Media(args.file)
      if (media.type !== 'image') {
        return
      }
      if (args.pageNumber !== undefined) {
        params.onSetPageImageUrl(args.pageNumber, media.url)
      } else {
        params.onBannerChange?.(media.url)
      }
      params.onMediaAdd?.(media)
    } catch (e) {
      params.setError(e instanceof Error ? e.message : t('upload.error.failed'))
    } finally {
      params.setUploading(false)
    }
  }
}
