import { createApp, h, ref } from 'vue'
import { NImage, NImageGroup } from 'naive-ui'

interface PreviewOptions {
  onStart?: () => void
  onError?: (e: Event) => void
  showToolbar?: boolean
}

class ImagePreview {
  private static instance: {
    app: any
    container: HTMLElement
  } | null = null

  static async preview(
    sources: string | File | (string | File)[], 
    index = 0,
    options: PreviewOptions = {},
  ) {
    try {
      const urls = await this.normalizeImageSources(
        Array.isArray(sources) ? sources : [sources]
      )

      if (!urls.length) {
        console.warn('[ImagePreview] No valid image sources')
        return
      }

      this.destroy()
      options.onStart?.()

      const container = document.createElement('div')
      container.style.display = 'none'
      document.body.appendChild(container)

      const app = createApp({
        setup() {
          const imageRef = ref<InstanceType<typeof NImage> | null>(null)

          return () => {
            if (urls.length === 1) {
              return h(NImage, {
                ref: imageRef,
                src: urls[0],
                previewDisabled: false,
                preview: true,
                showToolbar: options.showToolbar ?? true,
                style: {
                  display: 'none'
                },
                onLoad: () => {
                  imageRef.value?.click()
                }
              })
            } else {
              return h(NImageGroup, {
                showToolbar: options.showToolbar ?? true,
                currentIndex: index
              }, {
                default: () => urls.map((url, i) => {
                  const imgRef = ref<InstanceType<typeof NImage> | null>(null)
                  return h(NImage, {
                    ref: i === index ? imgRef : undefined,
                    src: url,
                    previewDisabled: false,
                    preview: true,
                    style: {
                      display: 'none'
                    },
                    onLoad: i === index ? () => {
                      imgRef.value?.click()
                    } : undefined
                  })
                })
              })
            }
          }
        }
      })

      app.mount(container)
      this.instance = { app, container }

    } catch (error) {
      console.error('[ImagePreview] Error:', error)
      options.onError?.(error as Event)
    }
  }

  private static async normalizeImageSources(sources: (string | File)[]): Promise<string[]> {
    const urls: string[] = []

    for (const source of sources) {
      try {
        if (typeof source === 'string') {
          if (source.startsWith('data:') || source.startsWith('http')) {
            urls.push(source)
          } else {
            console.warn('[ImagePreview] Invalid image source:', source)
          }
        } else if (source instanceof File) {
          const url = await this.fileToUrl(source)
          urls.push(url)
        }
      } catch (error) {
        console.warn('[ImagePreview] Failed to process source:', source, error)
      }
    }

    return urls
  }

  private static fileToUrl(file: File): Promise<string> {
    return new Promise((resolve, reject) => {
      if (!file.type.startsWith('image/')) {
        reject(new Error('Not an image file'))
        return
      }

      const reader = new FileReader()
      reader.onload = () => resolve(reader.result as string)
      reader.onerror = reject
      reader.readAsDataURL(file)
    })
  }

  private static destroy() {
    if (this.instance) {
      const { app, container } = this.instance
      app.unmount()
      container.remove()
      this.instance = null
    }
  }

  static close() {
    this.destroy()
  }
}

export const previewImage = ImagePreview.preview.bind(ImagePreview)
export const closePreview = ImagePreview.close.bind(ImagePreview)