import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'

// Mock api/client.js — no real HTTP calls in unit tests (CLAUDE.md W4)
vi.mock('../../api/client.js', () => ({
  listCloudConnections: vi.fn(),
  disconnectCloud: vi.fn(),
  connectWebDav: vi.fn(),
  updateDefaultStorage: vi.fn(),
  renameCloudConnection: vi.fn(),
  getCloudFoldersByConnectionId: vi.fn(),
}))

import { useCloudConnectionsStore, saveLastFolder, loadLastFolder } from '../cloudConnections.js'
import * as api from '../../api/client.js'

beforeEach(() => {
  setActivePinia(createPinia())
  vi.clearAllMocks()
  // Clear sessionStorage between tests
  sessionStorage.clear()
})

afterEach(() => {
  sessionStorage.clear()
})

describe('useCloudConnectionsStore', () => {
  it('fetchConnections sets connections from API response', async () => {
    api.listCloudConnections.mockResolvedValue({
      items: [{ id: '1', provider: 'google_drive', status: 'ACTIVE' }],
    })
    const store = useCloudConnectionsStore()
    await store.fetchConnections()
    expect(store.connections).toHaveLength(1)
    expect(store.connections[0].provider).toBe('google_drive')
    expect(store.loading).toBe(false)
  })

  it('fetchConnections sets error on API failure', async () => {
    api.listCloudConnections.mockRejectedValue(new Error('Network error'))
    const store = useCloudConnectionsStore()
    await store.fetchConnections()
    expect(store.error).toBeTruthy()
    expect(store.connections).toHaveLength(0)
  })

  it('disconnect removes connection from state after API call', async () => {
    api.disconnectCloud.mockResolvedValue(null)
    const store = useCloudConnectionsStore()
    store.connections = [{ id: 'conn-1', provider: 'google_drive', status: 'ACTIVE' }]
    await store.disconnect('conn-1')
    expect(store.connections).toHaveLength(0)
    expect(api.disconnectCloud).toHaveBeenCalledWith('conn-1')
  })

  it('disconnectAll clears all connections', async () => {
    api.disconnectCloud.mockResolvedValue(null)
    const store = useCloudConnectionsStore()
    store.connections = [
      { id: 'a', provider: 'google_drive', status: 'ACTIVE' },
      { id: 'b', provider: 'onedrive', status: 'ACTIVE' },
    ]
    await store.disconnectAll()
    expect(store.connections).toHaveLength(0)
  })

  // Rename tests
  it('rename updates the connection in state on success', async () => {
    api.renameCloudConnection.mockResolvedValue({
      id: 'conn-1', provider: 'google_drive', display_name: 'My Drive',
    })
    const store = useCloudConnectionsStore()
    store.connections = [{ id: 'conn-1', provider: 'google_drive', display_name: 'Google Drive' }]
    await store.rename('conn-1', 'My Drive')
    expect(store.connections[0].display_name).toBe('My Drive')
    expect(api.renameCloudConnection).toHaveBeenCalledWith('conn-1', 'My Drive')
  })

  it('rename rejects on empty display name', async () => {
    const store = useCloudConnectionsStore()
    await expect(store.rename('conn-1', '')).rejects.toThrow()
  })

  it('rename rejects on whitespace-only display name', async () => {
    const store = useCloudConnectionsStore()
    await expect(store.rename('conn-1', '   ')).rejects.toThrow()
  })

  it('rename propagates API error', async () => {
    api.renameCloudConnection.mockRejectedValue(new Error('API error'))
    const store = useCloudConnectionsStore()
    store.connections = [{ id: 'conn-1', provider: 'google_drive', display_name: 'Google Drive' }]
    await expect(store.rename('conn-1', 'New Name')).rejects.toThrow('API error')
  })

  // Two same-provider connections render as separate roots
  it('two google_drive connections render as separate roots with UUID suffixes in defaultDisplayName', () => {
    const store = useCloudConnectionsStore()
    store.connections = [
      { id: 'aabb-ccdd-1', provider: 'google_drive', display_name: null },
      { id: 'eeff-gggg-2', provider: 'google_drive', display_name: null },
    ]
    const nameA = store.defaultDisplayName(store.connections[0])
    const nameB = store.defaultDisplayName(store.connections[1])
    // Both should contain "Google Drive" and a 4-char suffix
    expect(nameA).toContain('Google Drive')
    expect(nameB).toContain('Google Drive')
    expect(nameA).toContain('aabb')
    expect(nameB).toContain('eeff')
  })

  it('single connection has no suffix in defaultDisplayName', () => {
    const store = useCloudConnectionsStore()
    store.connections = [{ id: 'conn-1', provider: 'google_drive' }]
    expect(store.defaultDisplayName(store.connections[0])).toBe('Google Drive')
  })

  // Connection UUID based URLs
  it('selectConnection sets selectedConnectionId', () => {
    const store = useCloudConnectionsStore()
    store.connections = [{ id: 'uuid-123', provider: 'onedrive' }]
    store.selectConnection('uuid-123')
    expect(store.selectedConnectionId).toBe('uuid-123')
    expect(store.selectedConnection?.id).toBe('uuid-123')
  })

  // Session storage for folder navigation
  it('saveLastFolder stores folder in sessionStorage', () => {
    saveLastFolder('conn-abc', 'Documents/Work')
    expect(sessionStorage.getItem('docuvault:cloud:folder:conn-abc')).toBe('Documents/Work')
  })

  it('loadLastFolder retrieves stored folder', () => {
    sessionStorage.setItem('docuvault:cloud:folder:conn-xyz', 'Photos')
    expect(loadLastFolder('conn-xyz')).toBe('Photos')
  })

  it('saveLastFolder removes key for root folder', () => {
    sessionStorage.setItem('docuvault:cloud:folder:conn-abc', 'Docs')
    saveLastFolder('conn-abc', 'root')
    expect(sessionStorage.getItem('docuvault:cloud:folder:conn-abc')).toBeNull()
  })

  it('loadLastFolder returns null when nothing stored', () => {
    expect(loadLastFolder('nonexistent')).toBeNull()
  })

  it('sessionStorage stores only folder references, not tokens', () => {
    // Ensure save only stores the folderId string under the namespaced key
    saveLastFolder('conn-123', 'Projects/Secret')
    const stored = sessionStorage.getItem('docuvault:cloud:folder:conn-123')
    expect(stored).toBe('Projects/Secret')
    // Stored value is a plain string path, not a JSON object with credentials
    expect(typeof stored).toBe('string')
    expect(stored.startsWith('{')).toBe(false)
  })
})
