import { describe, it, expect, beforeEach, vi } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { useFoldersStore } from '../folders.js'

// ── API mock ──────────────────────────────────────────────────────────────────

const mockListFolders = vi.fn()
const mockCreateFolder = vi.fn()
const mockGetFolder = vi.fn()
const mockRenameFolder = vi.fn()
const mockDeleteFolder = vi.fn()

vi.mock('../../api/client.js', () => ({
  listFolders: (...a) => mockListFolders(...a),
  createFolder: (...a) => mockCreateFolder(...a),
  getFolder: (...a) => mockGetFolder(...a),
  renameFolder: (...a) => mockRenameFolder(...a),
  deleteFolder: (...a) => mockDeleteFolder(...a),
  moveDocument: vi.fn(),
}))

// ── Helpers ───────────────────────────────────────────────────────────────────

function makeFolder(overrides = {}) {
  return {
    id: overrides.id ?? 'folder-1',
    name: overrides.name ?? 'Test',
    parent_id: overrides.parent_id ?? null,
    has_children: overrides.has_children ?? false,
    created_at: '2026-01-01T00:00:00Z',
  }
}

// ── Tests ─────────────────────────────────────────────────────────────────────

describe('foldersStore', () => {
  beforeEach(() => {
    setActivePinia(createPinia())
    vi.clearAllMocks()
  })

  // ── fetchFolders ─────────────────────────────────────────────────────────

  it('fetchFolders(null) sets folders and rootFolders', async () => {
    const roots = [makeFolder({ id: 'r1', name: 'Root1' })]
    mockListFolders.mockResolvedValue({ items: roots })

    const store = useFoldersStore()
    await store.fetchFolders(null)

    expect(store.folders).toEqual(roots)
    expect(store.rootFolders).toEqual(roots)
  })

  it('fetchFolders(parentId) sets folders but NOT rootFolders', async () => {
    const children = [makeFolder({ id: 'c1', name: 'Child', parent_id: 'parent-1' })]
    mockListFolders.mockResolvedValue({ items: children })

    const store = useFoldersStore()
    store.rootFolders = [makeFolder({ id: 'r1' })] // pre-populate rootFolders

    await store.fetchFolders('parent-1')

    expect(store.folders).toEqual(children)
    expect(store.rootFolders).toEqual([makeFolder({ id: 'r1' })]) // unchanged
  })

  it('fetchRootFolders sets rootFolders without touching folders', async () => {
    const roots = [makeFolder({ id: 'r1' })]
    mockListFolders.mockResolvedValue({ items: roots })

    const store = useFoldersStore()
    store.folders = [makeFolder({ id: 'sub1', parent_id: 'r1' })] // simulate being inside a folder

    await store.fetchRootFolders()

    expect(store.rootFolders).toEqual(roots)
    expect(store.folders[0].id).toBe('sub1') // unchanged
  })

  // ── createFolder ─────────────────────────────────────────────────────────

  it('createFolder(name, null) adds to both folders and rootFolders', async () => {
    const newFolder = makeFolder({ id: 'new-1', name: 'NewRoot' })
    mockCreateFolder.mockResolvedValue(newFolder)

    const store = useFoldersStore()
    await store.createFolder('NewRoot', null)

    expect(store.folders.some(f => f.id === 'new-1')).toBe(true)
    expect(store.rootFolders.some(f => f.id === 'new-1')).toBe(true)
  })

  it('createFolder(name, parentId) adds to folders but NOT rootFolders', async () => {
    const newFolder = makeFolder({ id: 'sub-1', name: 'SubFolder', parent_id: 'parent-1' })
    mockCreateFolder.mockResolvedValue(newFolder)

    const store = useFoldersStore()
    await store.createFolder('SubFolder', 'parent-1')

    expect(store.folders.some(f => f.id === 'sub-1')).toBe(true)
    expect(store.rootFolders.some(f => f.id === 'sub-1')).toBe(false)
  })

  it('createFolder bumps treeVersion', async () => {
    mockCreateFolder.mockResolvedValue(makeFolder())

    const store = useFoldersStore()
    const before = store.treeVersion
    await store.createFolder('Test', null)

    expect(store.treeVersion).toBe(before + 1)
  })

  it('createFolder throws on API error and propagates', async () => {
    mockCreateFolder.mockRejectedValue(new Error('409 Conflict'))

    const store = useFoldersStore()
    await expect(store.createFolder('Dup', null)).rejects.toThrow('409 Conflict')
  })

  // ── renameFolder ─────────────────────────────────────────────────────────

  it('renameFolder updates folder in both folders and rootFolders', async () => {
    const original = makeFolder({ id: 'f1', name: 'OldName' })
    const updated = { ...original, name: 'NewName' }
    mockRenameFolder.mockResolvedValue(updated)

    const store = useFoldersStore()
    store.folders = [original]
    store.rootFolders = [original]

    await store.renameFolder('f1', 'NewName')

    expect(store.folders[0].name).toBe('NewName')
    expect(store.rootFolders[0].name).toBe('NewName')
  })

  it('renameFolder bumps treeVersion', async () => {
    const folder = makeFolder({ id: 'f1' })
    mockRenameFolder.mockResolvedValue({ ...folder, name: 'New' })

    const store = useFoldersStore()
    store.folders = [folder]
    const before = store.treeVersion

    await store.renameFolder('f1', 'New')

    expect(store.treeVersion).toBe(before + 1)
  })

  // ── deleteFolder ─────────────────────────────────────────────────────────

  it('deleteFolder removes from both folders and rootFolders', async () => {
    mockDeleteFolder.mockResolvedValue(null)

    const store = useFoldersStore()
    const folder = makeFolder({ id: 'del-1' })
    store.folders = [folder]
    store.rootFolders = [folder]

    await store.deleteFolder('del-1')

    expect(store.folders.some(f => f.id === 'del-1')).toBe(false)
    expect(store.rootFolders.some(f => f.id === 'del-1')).toBe(false)
  })

  it('deleteFolder bumps treeVersion', async () => {
    mockDeleteFolder.mockResolvedValue(null)

    const store = useFoldersStore()
    store.folders = [makeFolder({ id: 'del-1' })]
    const before = store.treeVersion

    await store.deleteFolder('del-1')

    expect(store.treeVersion).toBe(before + 1)
  })

  // ── navigateTo ───────────────────────────────────────────────────────────

  it('navigateTo(null) clears folders and breadcrumb', async () => {
    const store = useFoldersStore()
    store.folders = [makeFolder()]
    store.breadcrumb = [{ id: 'x', name: 'X' }]

    await store.navigateTo(null)

    expect(store.folders).toEqual([])
    expect(store.breadcrumb).toEqual([])
  })

  it('navigateTo(id) sets breadcrumb from API', async () => {
    const crumbs = [{ id: 'r1', name: 'Root' }, { id: 'f1', name: 'Test' }]
    mockGetFolder.mockResolvedValue({ id: 'f1', name: 'Test', breadcrumb: crumbs })

    const store = useFoldersStore()
    await store.navigateTo('f1')

    expect(store.breadcrumb).toEqual(crumbs)
  })

  it('navigateTo(id) sets breadcrumb to [] on API error', async () => {
    mockGetFolder.mockRejectedValue(new Error('404'))

    const store = useFoldersStore()
    await store.navigateTo('bad-id')

    expect(store.breadcrumb).toEqual([])
  })

  it('navigateTo sets currentFolderId', async () => {
    mockGetFolder.mockResolvedValue({ id: 'f1', name: 'Test', breadcrumb: [] })

    const store = useFoldersStore()
    await store.navigateTo('f1')

    expect(store.currentFolderId).toBe('f1')
  })
})
