import { describe, it, expect, beforeEach, vi } from 'vitest'
import { mount, flushPromises } from '@vue/test-utils'
import { createPinia, setActivePinia, defineStore } from 'pinia'
import { nextTick } from 'vue'
import StorageBrowser from '../StorageBrowser.vue'

// ── Minimal store stubs ────────────────────────────────────────────────────────
const useToastStore = defineStore('toast', {
  state: () => ({ messages: [] }),
  actions: {
    show: vi.fn(),
  },
})

const useDocsStore = defineStore('documents', {
  state: () => ({
    documents: [],
    loading: false,
    searchQuery: '',
    sortField: 'created_at',
    sortOrder: 'desc',
    currentFolderId: null,
  }),
  actions: {
    moveToFolder: vi.fn(),
  },
})

const globalStubs = {
  BreadcrumbBar: true,
  SearchBar: true,
  SortControls: true,
  DropZone: true,
  UploadProgress: true,
  TopicBadge: true,
  AppIcon: true,
  EmptyState: true,
}

const FOLDERS = [{ id: 'f1', name: 'Archive', created_at: '2025-01-01T00:00:00Z' }]
const FILES = [{ id: 'd1', original_name: 'report.pdf', size_bytes: 1024, created_at: '2025-01-01T00:00:00Z', topics: [] }]

describe('UX-11: Drag-to-move document onto folder row', () => {
  beforeEach(() => {
    setActivePinia(createPinia())
  })

  it('dragOverFolderId set on @dragover applies bg-amber-50 ring-2 ring-inset ring-amber-300 to that folder row', async () => {
    const wrapper = mount(StorageBrowser, {
      props: { mode: 'local', folders: FOLDERS, files: FILES, rootFolders: [] },
      global: { stubs: globalStubs },
    })

    // Simulate a dragstart on the file row to set draggingFile
    const fileRow = wrapper.find('[draggable="true"]')
    const dtMock = { effectAllowed: '', setData: vi.fn(), types: [] }
    await fileRow.trigger('dragstart', { dataTransfer: dtMock })

    // Simulate dragover on folder row
    const folderRow = wrapper.findAll('.grid-cols-\\[2rem_1fr_6rem_8rem_6rem\\]').find(el =>
      el.classes().includes('cursor-pointer') && el.attributes('class')?.includes('hover:bg-gray-50')
    )
    // Find the folder row by looking for the amber folder icon
    const allRows = wrapper.findAll('[class*="px-4 py-2.5"]')
    const fRow = allRows.find(r => r.text().includes('Archive'))
    await fRow.trigger('dragover', { preventDefault: vi.fn() })

    // Now the folder row should have the amber ring + bg
    await nextTick()
    expect(fRow.classes()).toContain('bg-amber-50')
    expect(fRow.classes()).toContain('ring-2')
    expect(fRow.classes()).toContain('ring-inset')
    expect(fRow.classes()).toContain('ring-amber-300')
  })

  it('drop on folder emits file-move with { fileId, folderId }', async () => {
    const wrapper = mount(StorageBrowser, {
      props: { mode: 'local', folders: FOLDERS, files: FILES, rootFolders: [] },
      global: { stubs: globalStubs },
    })

    // Dragstart on file row
    const fileRow = wrapper.find('[draggable="true"]')
    const dtMock = { effectAllowed: '', setData: vi.fn() }
    await fileRow.trigger('dragstart', { dataTransfer: dtMock })

    // Drop on folder row
    const allRows = wrapper.findAll('[class*="px-4 py-2.5"]')
    const fRow = allRows.find(r => r.text().includes('Archive'))
    await fRow.trigger('drop', { preventDefault: vi.fn() })

    await flushPromises()
    await nextTick()

    expect(wrapper.emitted('file-move')).toBeTruthy()
    expect(wrapper.emitted('file-move')[0][0]).toEqual({ fileId: 'd1', folderId: 'f1' })
  })

  it('file-row click is suppressed when draggingFile is non-null', async () => {
    const wrapper = mount(StorageBrowser, {
      props: { mode: 'local', folders: FOLDERS, files: FILES, rootFolders: [] },
      global: { stubs: globalStubs },
    })

    // Dragstart to set draggingFile
    const fileRow = wrapper.find('[draggable="true"]')
    const dtMock = { effectAllowed: '', setData: vi.fn() }
    await fileRow.trigger('dragstart', { dataTransfer: dtMock })

    // While draggingFile is set, clicking the file row should NOT emit file-open
    await fileRow.trigger('click')

    expect(wrapper.emitted('file-open')).toBeFalsy()
  })

  it('dragend resets draggingFile after nextTick (click-after-drag guard)', async () => {
    const wrapper = mount(StorageBrowser, {
      props: { mode: 'local', folders: FOLDERS, files: FILES, rootFolders: [] },
      global: { stubs: globalStubs },
    })

    // Dragstart to set draggingFile
    const fileRow = wrapper.find('[draggable="true"]')
    const dtMock = { effectAllowed: '', setData: vi.fn() }
    await fileRow.trigger('dragstart', { dataTransfer: dtMock })

    // draggingFile should be set
    expect(wrapper.vm.draggingFile).not.toBeNull()

    // Trigger dragend
    await fileRow.trigger('dragend')
    await nextTick()

    // After nextTick, draggingFile should be null
    expect(wrapper.vm.draggingFile).toBeNull()
  })
})

describe('UX-11 (toast wiring): doMove emits toast via FileManagerView', () => {
  beforeEach(() => {
    setActivePinia(createPinia())
  })

  it('successful moveToFolder triggers useToastStore.show("Document moved", "success")', async () => {
    // Import FileManagerView inline to test toast wiring
    const { useDocumentsStore } = await import('../../../stores/documents.js')
    const { useFoldersStore } = await import('../../../stores/folders.js')
    const { useToastStore } = await import('../../../stores/toast.js')
    const { useRouter, useRoute } = await import('vue-router')

    // We test the doMove function logic directly
    // Toast store should have show method
    const toastStore = useToastStore()
    const docsStore = useDocumentsStore()

    vi.spyOn(docsStore, 'moveToFolder').mockResolvedValue({})
    vi.spyOn(toastStore, 'show')

    // Simulate what FileManagerView.doMove does
    async function doMove(docId, folderId) {
      try {
        await docsStore.moveToFolder(docId, folderId)
        toastStore.show('Document moved', 'success')
      } catch (e) {
        toastStore.show('Move failed: ' + (e.message || 'unknown error'), 'error')
      }
    }

    await doMove('d1', 'f1')

    expect(toastStore.show).toHaveBeenCalledWith('Document moved', 'success')
  })

  it('failed moveToFolder triggers useToastStore.show("Move failed: ...", "error")', async () => {
    const { useDocumentsStore } = await import('../../../stores/documents.js')
    const { useToastStore } = await import('../../../stores/toast.js')

    const toastStore = useToastStore()
    const docsStore = useDocumentsStore()

    vi.spyOn(docsStore, 'moveToFolder').mockRejectedValue(new Error('Network error'))
    vi.spyOn(toastStore, 'show')

    async function doMove(docId, folderId) {
      try {
        await docsStore.moveToFolder(docId, folderId)
        toastStore.show('Document moved', 'success')
      } catch (e) {
        toastStore.show('Move failed: ' + (e.message || 'unknown error'), 'error')
      }
    }

    await doMove('d1', 'f1')

    expect(toastStore.show).toHaveBeenCalledWith('Move failed: Network error', 'error')
  })
})
