import { describe, it, expect, vi, beforeEach } from 'vitest'
import { mount, flushPromises } from '@vue/test-utils'

// Mock api/client.js
vi.mock('../../../api/client.js', () => ({
  adminListUsers: vi.fn(),
  adminGetUserQuota: vi.fn(),
  adminUpdateQuota: vi.fn(),
}))

import AdminQuotasTab from '../AdminQuotasTab.vue'
import * as api from '../../../api/client.js'

const MB = 1048576

function makeUser(id, email) {
  return { id, email, handle: email.split('@')[0], role: 'user', is_active: true }
}

function makeQuota(userId, usedMB, limitMB) {
  return {
    user_id: userId,
    used_bytes: usedMB * MB,
    limit_bytes: limitMB * MB,
  }
}

beforeEach(() => {
  vi.clearAllMocks()
})

// ── onMounted: loads users + quotas ──────────────────────────────────────────

describe('AdminQuotasTab — onMounted', () => {
  it('calls adminListUsers() on mount', async () => {
    api.adminListUsers.mockResolvedValue({ items: [] })
    mount(AdminQuotasTab)
    await flushPromises()
    expect(api.adminListUsers).toHaveBeenCalledTimes(1)
  })

  it('shows "No users yet" empty state when API returns empty list', async () => {
    api.adminListUsers.mockResolvedValue({ items: [] })
    const w = mount(AdminQuotasTab)
    await flushPromises()
    expect(w.text()).toContain('No users yet')
  })

  it('calls adminGetUserQuota for each user', async () => {
    api.adminListUsers.mockResolvedValue({
      items: [makeUser('u1', 'alice@example.com'), makeUser('u2', 'bob@example.com')],
    })
    api.adminGetUserQuota
      .mockResolvedValueOnce(makeQuota('u1', 10, 100))
      .mockResolvedValueOnce(makeQuota('u2', 50, 200))

    mount(AdminQuotasTab)
    await flushPromises()

    expect(api.adminGetUserQuota).toHaveBeenCalledWith('u1')
    expect(api.adminGetUserQuota).toHaveBeenCalledWith('u2')
  })

  it('displays quota data in the table', async () => {
    api.adminListUsers.mockResolvedValue({
      items: [makeUser('u1', 'alice@example.com')],
    })
    api.adminGetUserQuota.mockResolvedValue(makeQuota('u1', 10, 100))

    const w = mount(AdminQuotasTab)
    await flushPromises()

    expect(w.text()).toContain('alice@example.com')
    // 10 MB used, 100 MB limit
    expect(w.text()).toContain('10 MB')
    expect(w.text()).toContain('100 MB')
  })
})

// ── saveQuota: calls adminUpdateQuota(id, bytes) ──────────────────────────────

describe('AdminQuotasTab — saveQuota', () => {
  it('calls adminUpdateQuota with user id and new limit in bytes on save', async () => {
    api.adminListUsers.mockResolvedValue({
      items: [makeUser('u1', 'alice@example.com')],
    })
    api.adminGetUserQuota.mockResolvedValue(makeQuota('u1', 10, 100))
    api.adminUpdateQuota.mockResolvedValue({
      user_id: 'u1',
      used_bytes: 10 * MB,
      limit_bytes: 200 * MB,
      warning: false,
    })

    const w = mount(AdminQuotasTab)
    await flushPromises()

    // Click "Edit" button
    const editBtn = w.find('button')
    expect(editBtn.text()).toContain('Edit')
    await editBtn.trigger('click')
    await w.vm.$nextTick()

    // Change the limit input to 200 MB
    const input = w.find('input[type="number"]')
    await input.setValue(200)

    // Click "Save"
    const saveBtn = w.findAll('button').find(b => b.text().includes('Save'))
    await saveBtn.trigger('click')
    await flushPromises()

    expect(api.adminUpdateQuota).toHaveBeenCalledWith('u1', 200 * MB)
  })

  it('shows warning text when API response has warning: true', async () => {
    api.adminListUsers.mockResolvedValue({
      items: [makeUser('u1', 'alice@example.com')],
    })
    api.adminGetUserQuota.mockResolvedValue(makeQuota('u1', 90, 100))
    api.adminUpdateQuota.mockResolvedValue({
      user_id: 'u1',
      used_bytes: 90 * MB,
      limit_bytes: 50 * MB, // below current usage
      warning: true,
    })

    const w = mount(AdminQuotasTab)
    await flushPromises()

    // Enter edit mode
    await w.find('button').trigger('click')
    await w.vm.$nextTick()

    // Set limit below current usage
    const input = w.find('input[type="number"]')
    await input.setValue(50)

    // Save
    const saveBtn = w.findAll('button').find(b => b.text().includes('Save'))
    await saveBtn.trigger('click')
    await flushPromises()

    // Warning text must appear
    expect(w.text()).toMatch(/below current usage|uploads will be blocked/i)
  })
})
