import { beforeEach, describe, expect, it, vi } from 'vitest'
import {
  fetchAppearancePrefs,
  saveAppearancePrefsToServer,
  syncAppearancePrefs
} from './appearancePrefs.js'
import { setThemePreference } from './userPreferences.js'

const USER_ID = 'appearance-sync-user'

vi.mock('./api.js', () => ({
  apiJson: vi.fn()
}))

import { apiJson } from './api.js'

const mockedApiJson = vi.mocked(apiJson)

describe('appearancePrefs', () => {
  beforeEach(() => {
    localStorage.clear()
    vi.clearAllMocks()
  })

  it('fetchAppearancePrefs returns defaults when not authenticated', async () => {
    await expect(fetchAppearancePrefs()).resolves.toEqual({
      theme: 'auto',
      colorScheme: 'auto',
      persisted: false
    })
    expect(mockedApiJson).not.toHaveBeenCalled()
  })

  it('syncAppearancePrefs applies server prefs after cache wipe', async () => {
    localStorage.setItem('active_userid', USER_ID)
    mockedApiJson.mockResolvedValueOnce({
      theme: 'ocean',
      colorScheme: 'dark',
      persisted: true
    })

    const changed = vi.fn()
    window.addEventListener('appearance-changed', changed)

    await syncAppearancePrefs(USER_ID)

    expect(localStorage.getItem(`user_pref_theme_${USER_ID}`)).toBe('ocean')
    expect(localStorage.getItem(`user_pref_color_scheme_${USER_ID}`)).toBe('dark')
    expect(changed).toHaveBeenCalledTimes(1)
  })

  it('syncAppearancePrefs uploads local prefs when server has none', async () => {
    localStorage.setItem('active_userid', USER_ID)
    setThemePreference(USER_ID, 'material')
    mockedApiJson
      .mockResolvedValueOnce({ theme: 'auto', colorScheme: 'auto', persisted: false })
      .mockResolvedValueOnce({ theme: 'material', colorScheme: 'auto', persisted: true })

    await syncAppearancePrefs(USER_ID)

    expect(mockedApiJson).toHaveBeenCalledTimes(2)
    expect(mockedApiJson).toHaveBeenLastCalledWith('/api/auth/appearance-prefs', {
      method: 'PUT',
      body: JSON.stringify({ theme: 'material', colorScheme: 'auto' })
    })
  })

  it('saveAppearancePrefsToServer skips when not authenticated', async () => {
    await saveAppearancePrefsToServer('ocean', 'light')
    expect(mockedApiJson).not.toHaveBeenCalled()
  })

  it('syncAppearancePrefs skips server sync when userId does not match active session', async () => {
    localStorage.setItem('active_userid', 'session-user')
    setThemePreference('other-user', 'ocean')
    mockedApiJson.mockResolvedValue({
      theme: 'material',
      colorScheme: 'dark',
      persisted: true
    })

    await syncAppearancePrefs('other-user')

    expect(mockedApiJson).not.toHaveBeenCalled()
    expect(localStorage.getItem('user_pref_theme_other-user')).toBe('ocean')
  })

  it('syncAppearancePrefs skips server sync when active session is missing', async () => {
    setThemePreference(USER_ID, 'ocean')

    await syncAppearancePrefs(USER_ID)

    expect(mockedApiJson).not.toHaveBeenCalled()
    expect(localStorage.getItem(`user_pref_theme_${USER_ID}`)).toBe('ocean')
  })
})
