import { beforeEach, describe, expect, it, vi } from 'vitest'

import {
  assignAdminRolePermissions,
  assignAdminUserHotels,
  assignAdminUserRoles,
  createAdminHotel,
  createAdminMenu,
  createAdminRole,
  createAdminUser,
  fetchAdminAudits,
  fetchAdminHotels,
  fetchAdminMenus,
  fetchAdminPermissions,
  fetchAdminRoleDetail,
  fetchAdminRoles,
  fetchAdminUserDetail,
  fetchAdminUsers,
  resetAdminUserPassword,
  updateAdminHotel,
  updateAdminHotelStatus,
  updateAdminMenu,
  updateAdminRole,
  updateAdminUser,
} from '@/services/systemAdminService'

const jsonHeaders = {
  headers: {
    get: (name: string) => (name.toLowerCase() === 'content-type' ? 'application/json' : null),
  },
}

function mockJsonResponse(payload: unknown): Response {
  return {
    ok: true,
    status: 200,
    json: async () => payload,
    text: async () => JSON.stringify(payload),
    ...jsonHeaders,
  } as Response
}

describe('systemAdminService', () => {
  beforeEach(() => {
    vi.restoreAllMocks()
    sessionStorage.clear()
  })

  it('fetches admin users with filters', async () => {
    const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
      mockJsonResponse({
        items: [],
        page: {
          page_num: 2,
          page_size: 10,
          total: 0,
        },
      }),
    )

    await fetchAdminUsers({
      keyword: 'admin',
      user_status: 'ACTIVE',
      page_num: 2,
      page_size: 10,
    })

    expect(fetchMock).toHaveBeenCalledWith(
      '/api/admin/users?keyword=admin&user_status=ACTIVE&page_num=2&page_size=10',
      expect.objectContaining({ method: 'GET' }),
    )
  })

  it('fetches role, menu, hotel lists and details from admin endpoints', async () => {
    const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(mockJsonResponse({ items: [], page: {} }))

    await fetchAdminRoles({ role_status: 'DISABLED' })
    await fetchAdminMenus({ menu_status: 'ACTIVE' })
    await fetchAdminHotels({ hotel_status: 'ACTIVE' })
    await fetchAdminUserDetail('10001')
    await fetchAdminRoleDetail('20001')

    expect(fetchMock).toHaveBeenNthCalledWith(
      1,
      '/api/admin/roles?role_status=DISABLED',
      expect.objectContaining({ method: 'GET' }),
    )
    expect(fetchMock).toHaveBeenNthCalledWith(
      2,
      '/api/admin/menus?menu_status=ACTIVE',
      expect.objectContaining({ method: 'GET' }),
    )
    expect(fetchMock).toHaveBeenNthCalledWith(
      3,
      '/api/admin/hotels?hotel_status=ACTIVE',
      expect.objectContaining({ method: 'GET' }),
    )
    expect(fetchMock).toHaveBeenNthCalledWith(
      4,
      '/api/admin/users/10001',
      expect.objectContaining({ method: 'GET' }),
    )
    expect(fetchMock).toHaveBeenNthCalledWith(
      5,
      '/api/admin/roles/20001',
      expect.objectContaining({ method: 'GET' }),
    )
  })

  it('fetches the readonly permission list', async () => {
    const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
      mockJsonResponse([
        {
          id: '1',
          permission_code: 'SYSTEM_USER_MANAGE',
          permission_name: '用户管理',
          permission_group: 'SYSTEM',
          permission_status: 'ACTIVE',
        },
      ]),
    )

    const result = await fetchAdminPermissions()

    expect(fetchMock).toHaveBeenCalledWith('/api/admin/permissions', expect.objectContaining({ method: 'GET' }))
    expect(result[0]?.permission_code).toBe('SYSTEM_USER_MANAGE')
  })

  it('sends admin user write operations to backend endpoints', async () => {
    const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(mockJsonResponse({ id: '10001' }))

    await createAdminUser({
      username: 'operator',
      initial_password: 'User@123456',
      display_name: 'Operator',
      user_status: 'ACTIVE',
      role_ids: ['20001'],
      hotel_ids: ['HOTEL-TEST'],
      default_hotel_id: 'HOTEL-TEST',
    })
    await updateAdminUser('10001', {
      display_name: 'Operator A',
      user_status: 'DISABLED',
    })
    await assignAdminUserRoles('10001', {
      role_ids: ['20002'],
    })
    await assignAdminUserHotels('10001', {
      hotel_ids: ['HOTEL-TEST'],
      default_hotel_id: 'HOTEL-TEST',
    })
    await resetAdminUserPassword('10001')

    expect(fetchMock).toHaveBeenNthCalledWith(
      1,
      '/api/admin/users',
      expect.objectContaining({ method: 'POST' }),
    )
    expect(fetchMock).toHaveBeenNthCalledWith(
      2,
      '/api/admin/users/10001',
      expect.objectContaining({ method: 'PUT' }),
    )
    expect(fetchMock).toHaveBeenNthCalledWith(
      3,
      '/api/admin/users/10001/roles',
      expect.objectContaining({ method: 'PUT' }),
    )
    expect(fetchMock).toHaveBeenNthCalledWith(
      4,
      '/api/admin/users/10001/hotels',
      expect.objectContaining({ method: 'PUT' }),
    )
    expect(fetchMock).toHaveBeenNthCalledWith(
      5,
      '/api/admin/users/10001/password-reset',
      expect.objectContaining({ method: 'POST', body: JSON.stringify({}) }),
    )
  })

  it('sends role, menu, hotel writes and audit queries to admin endpoints', async () => {
    const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(mockJsonResponse({ id: '1', items: [], page: {} }))

    await createAdminRole({ role_code: 'CUSTOM_ROLE', role_name: 'Custom role', role_status: 'ACTIVE' })
    await updateAdminRole('20001', { role_name: 'Custom role A', role_status: 'DISABLED' })
    await assignAdminRolePermissions('20001', { permission_ids: ['30001'] })
    await createAdminMenu({
      menu_code: 'CUSTOM_MENU',
      menu_name: 'Custom menu',
      menu_type: 'PAGE',
      visible: false,
      menu_status: 'DISABLED',
    })
    await updateAdminMenu('40001', {
      menu_name: 'Custom menu A',
      menu_type: 'PAGE',
      visible: true,
      menu_status: 'ACTIVE',
    })
    await createAdminHotel({
      hotel_id: 'HOTEL-BKK',
      hotel_name: 'Bangkok Hotel',
      time_zone: 'Asia/Bangkok',
    })
    await updateAdminHotel('HOTEL-BKK', {
      hotel_name: 'Bangkok Hotel A',
      time_zone: 'Asia/Bangkok',
    })
    await updateAdminHotelStatus('HOTEL-BKK', { hotel_status: 'ACTIVE' })
    await fetchAdminAudits({ target_type: 'PLATFORM_USER', page_num: 1, page_size: 20 })

    expect(fetchMock).toHaveBeenNthCalledWith(1, '/api/admin/roles', expect.objectContaining({ method: 'POST' }))
    expect(fetchMock).toHaveBeenNthCalledWith(2, '/api/admin/roles/20001', expect.objectContaining({ method: 'PUT' }))
    expect(fetchMock).toHaveBeenNthCalledWith(
      3,
      '/api/admin/roles/20001/permissions',
      expect.objectContaining({ method: 'PUT' }),
    )
    expect(fetchMock).toHaveBeenNthCalledWith(4, '/api/admin/menus', expect.objectContaining({ method: 'POST' }))
    expect(fetchMock).toHaveBeenNthCalledWith(5, '/api/admin/menus/40001', expect.objectContaining({ method: 'PUT' }))
    expect(fetchMock).toHaveBeenNthCalledWith(6, '/api/admin/hotels', expect.objectContaining({ method: 'POST' }))
    expect(fetchMock).toHaveBeenNthCalledWith(
      7,
      '/api/admin/hotels/HOTEL-BKK',
      expect.objectContaining({ method: 'PUT' }),
    )
    expect(fetchMock).toHaveBeenNthCalledWith(
      8,
      '/api/admin/hotels/HOTEL-BKK/status',
      expect.objectContaining({ method: 'PUT' }),
    )
    expect(fetchMock).toHaveBeenNthCalledWith(
      9,
      '/api/admin/audits?target_type=PLATFORM_USER&page_num=1&page_size=20',
      expect.objectContaining({ method: 'GET' }),
    )
  })
})
