import { describe, expect, it, vi, beforeEach } from 'vitest'
import { flushPromises, mount } from '@vue/test-utils'
import { defineComponent } from 'vue'
import UserEditModal from '../UserEditModal.vue'
import type { AdminUser } from '@/types'

// Mock dependencies - 使用 vi.hoisted 确保顺序正确
const { updateMock, updateAttributeValuesMock } = vi.hoisted(() => ({
  updateMock: vi.fn(),
  updateAttributeValuesMock: vi.fn()
}))

vi.mock('@/stores/app', () => ({
  useAppStore: () => ({
    showError: vi.fn(),
    showSuccess: vi.fn()
  })
}))

vi.mock('@/composables/useClipboard', () => ({
  useClipboard: () => ({
    copyToClipboard: vi.fn().mockResolvedValue(true)
  })
}))

vi.mock('@/api/admin', () => ({
  adminAPI: {
    users: {
      update: updateMock
    },
    userAttributes: {
      updateUserAttributeValues: updateAttributeValuesMock
    }
  }
}))

vi.mock('vue-i18n', async () => {
  const actual = await vi.importActual<typeof import('vue-i18n')>('vue-i18n')
  return {
    ...actual,
    useI18n: () => ({
      t: (key: string) => key
    })
  }
})

function createMockUser(overrides: Partial<AdminUser> = {}): AdminUser {
  return {
    id: 1,
    email: 'test@example.com',
    username: 'testuser',
    notes: '',
    concurrency: 1,
    balance: 0,
    role: 'user',
    is_active: true,
    is_superuser: false,
    created_at: '2024-01-01T00:00:00Z',
    updated_at: '2024-01-01T00:00:00Z',
    sora_storage_quota_bytes: 10 * 1024 * 1024 * 1024,
    sora_storage_used_bytes: 0,
    ...overrides
  }
}

const BaseDialogStub = defineComponent({
  name: 'BaseDialog',
  props: ['show', 'title', 'width'],
  emits: ['close'],
  template: '<div v-if="show"><slot /><slot name="footer" /></div>'
})

const IconStub = defineComponent({
  name: 'Icon',
  props: ['name', 'size'],
  template: '<span class="icon">icon</span>'
})

const UserAttributeFormStub = defineComponent({
  name: 'UserAttributeForm',
  props: ['modelValue', 'userId'],
  emits: ['update:modelValue'],
  template: '<div class="user-attribute-form"></div>'
})

describe('UserEditModal', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    updateMock.mockResolvedValue({})
    updateAttributeValuesMock.mockResolvedValue({})
  })

  describe('表单初始化', () => {
    it('打开时填充用户数据', async () => {
      const user = createMockUser({
        email: 'user@example.com',
        username: 'myuser',
        concurrency: 5,
        sora_storage_quota_bytes: 20 * 1024 * 1024 * 1024
      })

      const wrapper = mount(UserEditModal, {
        props: { show: true, user },
        global: {
          stubs: {
            BaseDialog: BaseDialogStub,
            Icon: IconStub,
            UserAttributeForm: UserAttributeFormStub
          }
        }
      })

      await flushPromises()

      // 验证表单字段已填充
      const emailInput = wrapper.find('input[type="email"]')
      expect((emailInput.element as HTMLInputElement).value).toBe('user@example.com')

      // username 输入框是第二个 text input（第一个是密码）
      const textInputs = wrapper.findAll('input[type="text"]')
      // 找到 username 输入框（它有一个 label）
      const usernameInput = textInputs.find(input => {
        const parent = input.element.closest('div')
        return parent?.querySelector('label')?.textContent?.includes('admin.users.username')
      }) || textInputs[1]

      // 验证 concurrency
      const concurrencyInput = wrapper.find('input[type="number"]')
      expect((concurrencyInput.element as HTMLInputElement).value).toBe('5')

      // Sora quota 应该转换为 GB
      const soraQuotaInput = wrapper.findAll('input[type="number"]')[1]
      expect((soraQuotaInput.element as HTMLInputElement).value).toBe('20')
    })

    it('关闭后重新打开时重置表单', async () => {
      const user1 = createMockUser({ id: 1, email: 'user1@example.com' })
      const user2 = createMockUser({ id: 2, email: 'user2@example.com' })

      const wrapper = mount(UserEditModal, {
        props: { show: true, user: user1 },
        global: {
          stubs: {
            BaseDialog: BaseDialogStub,
            Icon: IconStub,
            UserAttributeForm: UserAttributeFormStub
          }
        }
      })

      await flushPromises()

      // 更换用户
      await wrapper.setProps({ user: user2 })
      await flushPromises()

      const emailInput = wrapper.find('input[type="email"]')
      expect((emailInput.element as HTMLInputElement).value).toBe('user2@example.com')
    })
  })

  describe('密码生成', () => {
    it('点击生成密码按钮生成随机密码', async () => {
      const user = createMockUser()

      const wrapper = mount(UserEditModal, {
        props: { show: true, user },
        global: {
          stubs: {
            BaseDialog: BaseDialogStub,
            Icon: IconStub,
            UserAttributeForm: UserAttributeFormStub
          }
        }
      })

      await flushPromises()

      const passwordInput = wrapper.find('input[placeholder="admin.users.enterNewPassword"]')
      expect((passwordInput.element as HTMLInputElement).value).toBe('')

      // 找到生成密码按钮（Refresh 图标按钮）
      const buttons = wrapper.findAll('button')
      const generateBtn = buttons.find(b => b.findComponent({ name: 'Icon' }).exists())
      await generateBtn?.trigger('click')

      // 密码应该被生成
      expect((passwordInput.element as HTMLInputElement).value.length).toBe(16)
    })
  })

  describe('更新用户', () => {
    it('成功更新用户信息', async () => {
      const user = createMockUser()

      const wrapper = mount(UserEditModal, {
        props: { show: true, user },
        global: {
          stubs: {
            BaseDialog: BaseDialogStub,
            Icon: IconStub,
            UserAttributeForm: UserAttributeFormStub
          }
        }
      })

      await flushPromises()

      await wrapper.find('form').trigger('submit.prevent')
      await flushPromises()

      expect(updateMock).toHaveBeenCalledWith(1, expect.objectContaining({
        email: 'test@example.com',
        username: 'testuser',
        concurrency: 1
      }))
    })

    it('更新时包含新密码', async () => {
      const user = createMockUser()

      const wrapper = mount(UserEditModal, {
        props: { show: true, user },
        global: {
          stubs: {
            BaseDialog: BaseDialogStub,
            Icon: IconStub,
            UserAttributeForm: UserAttributeFormStub
          }
        }
      })

      await flushPromises()

      // 设置密码
      const passwordInput = wrapper.find('input[placeholder="admin.users.enterNewPassword"]')
      await passwordInput.setValue('newpassword123')

      await wrapper.find('form').trigger('submit.prevent')
      await flushPromises()

      expect(updateMock).toHaveBeenCalledWith(1, expect.objectContaining({
        password: 'newpassword123'
      }))
    })

    it('更新 Sora 存储配额', async () => {
      const user = createMockUser()

      const wrapper = mount(UserEditModal, {
        props: { show: true, user },
        global: {
          stubs: {
            BaseDialog: BaseDialogStub,
            Icon: IconStub,
            UserAttributeForm: UserAttributeFormStub
          }
        }
      })

      await flushPromises()

      // 修改 Sora 配额（GB 单位）
      const soraQuotaInput = wrapper.findAll('input[type="number"]')[1]
      await soraQuotaInput.setValue(50)

      await wrapper.find('form').trigger('submit.prevent')
      await flushPromises()

      expect(updateMock).toHaveBeenCalledWith(1, expect.objectContaining({
        sora_storage_quota_bytes: 50 * 1024 * 1024 * 1024
      }))
    })

    it('更新失败时不会崩溃', async () => {
      updateMock.mockRejectedValue(new Error('Update failed'))

      const user = createMockUser()

      const wrapper = mount(UserEditModal, {
        props: { show: true, user },
        global: {
          stubs: {
            BaseDialog: BaseDialogStub,
            Icon: IconStub,
            UserAttributeForm: UserAttributeFormStub
          }
        }
      })

      await flushPromises()

      await wrapper.find('form').trigger('submit.prevent')
      await flushPromises()

      // 主要验证组件不会崩溃
      expect(wrapper.exists()).toBe(true)
    })

    it('成功更新后触发 success 事件', async () => {
      const user = createMockUser()

      const wrapper = mount(UserEditModal, {
        props: { show: true, user },
        global: {
          stubs: {
            BaseDialog: BaseDialogStub,
            Icon: IconStub,
            UserAttributeForm: UserAttributeFormStub
          }
        }
      })

      await flushPromises()

      await wrapper.find('form').trigger('submit.prevent')
      await flushPromises()

      expect(wrapper.emitted('success')).toBeTruthy()
      expect(wrapper.emitted('close')).toBeTruthy()
    })
  })

  describe('Sora 配额转换', () => {
    it('正确转换字节到 GB', async () => {
      const user = createMockUser({
        sora_storage_quota_bytes: 15 * 1024 * 1024 * 1024 // 15 GB
      })

      const wrapper = mount(UserEditModal, {
        props: { show: true, user },
        global: {
          stubs: {
            BaseDialog: BaseDialogStub,
            Icon: IconStub,
            UserAttributeForm: UserAttributeFormStub
          }
        }
      })

      await flushPromises()

      const soraQuotaInput = wrapper.findAll('input[type="number"]')[1]
      expect((soraQuotaInput.element as HTMLInputElement).value).toBe('15')
    })

    it('正确处理小数 GB', async () => {
      const user = createMockUser({
        sora_storage_quota_bytes: 5.5 * 1024 * 1024 * 1024 // 5.5 GB
      })

      const wrapper = mount(UserEditModal, {
        props: { show: true, user },
        global: {
          stubs: {
            BaseDialog: BaseDialogStub,
            Icon: IconStub,
            UserAttributeForm: UserAttributeFormStub
          }
        }
      })

      await flushPromises()

      const soraQuotaInput = wrapper.findAll('input[type="number"]')[1]
      const value = parseFloat((soraQuotaInput.element as HTMLInputElement).value)
      expect(value).toBeCloseTo(5.5, 1)
    })
  })

  describe('关闭对话框', () => {
    it('点击取消按钮触发 close 事件', async () => {
      const user = createMockUser()

      const wrapper = mount(UserEditModal, {
        props: { show: true, user },
        global: {
          stubs: {
            BaseDialog: BaseDialogStub,
            Icon: IconStub,
            UserAttributeForm: UserAttributeFormStub
          }
        }
      })

      await flushPromises()

      const cancelButton = wrapper.findAll('button').find(b => b.text().includes('common.cancel'))
      await cancelButton?.trigger('click')

      expect(wrapper.emitted('close')).toBeTruthy()
    })
  })
})
