import { describe, it, expect, vi } from 'vitest'
import { mount } from '@vue/test-utils'
import DevicePicker from '@/components/DevicePicker.vue'
import type { Device } from '@/types'

// Stub child components DevicePicker wraps
vi.mock('@/components/BaseBottomSheet.vue', () => ({
  default: {
    name: 'BaseBottomSheet',
    template: '<div class="bottom-sheet-stub"><slot /></div>',
    props: ['modelValue', 'label'],
    emits: ['update:modelValue'],
  },
}))
vi.mock('@/components/BaseButton.vue', () => ({
  default: {
    name: 'BaseButton',
    template: '<button :disabled="disabled" @click="$emit(\'click\')"><slot /></button>',
    props: ['variant', 'disabled'],
    emits: ['click'],
  },
}))

const makeDevice = (overrides: Partial<Device> = {}): Device => ({
  id: 1,
  mac: 'AA:BB:CC:DD:EE:FF',
  name: 'Living Room',
  orientation: 'landscape',
  model: 'v1',
  rotationIntervalMinutes: 60,
  wakeTimes: [],
  timezone: 'America/Chicago',
  uniquenessWindow: 30,
  rotationMode: 'oldest_upload',
  prioritizeNeverShown: false,
  linkedAt: '2026-01-01T00:00:00Z',
  lastSeenAt: null,
  nextPollExpectedAt: null,
  lockedImageId: null,
  currentImageId: null,
  ...overrides,
})

describe('DevicePicker', () => {
  const devices = [
    makeDevice({ id: 1, name: 'Living Room' }),
    makeDevice({ id: 2, name: 'Bedroom' }),
  ]

  function mountPicker(selected: number[] = []) {
    return mount(DevicePicker, {
      props: {
        modelValue: true,
        devices,
        selected,
      },
    })
  }

  // DP-01: Selecting a device emits update:selected with the device added
  it('checking a device emits update:selected with device id added', async () => {
    const wrapper = mountPicker([])

    const checkboxes = wrapper.findAll('input[type="checkbox"]')
    // Click the first checkbox (Living Room, id=1)
    await checkboxes[0].trigger('change')

    const emitted = wrapper.emitted('update:selected')
    expect(emitted).toBeTruthy()
    expect(emitted![0][0]).toEqual([1])
  })

  // DP-02: Deselecting a device emits update:selected with device id removed
  it('unchecking a device emits update:selected with device id removed', async () => {
    // Start with both selected
    const wrapper = mountPicker([1, 2])

    const checkboxes = wrapper.findAll('input[type="checkbox"]')
    // Click the first checkbox (Living Room, id=1) — it's currently checked, so this deselects
    await checkboxes[0].trigger('change')

    const emitted = wrapper.emitted('update:selected')
    expect(emitted).toBeTruthy()
    // Should emit [2] — Living Room removed
    expect(emitted![0][0]).toEqual([2])
  })

  // DP-03: Checkboxes reflect the selected prop
  it('checkboxes are checked for ids in selected prop', async () => {
    const wrapper = mountPicker([2])

    const checkboxes = wrapper.findAll('input[type="checkbox"]')
    expect((checkboxes[0].element as HTMLInputElement).checked).toBe(false) // id=1 not selected
    expect((checkboxes[1].element as HTMLInputElement).checked).toBe(true)  // id=2 selected
  })

  // DP-04: Confirm button disabled when nothing selected
  it('confirm button is disabled when selected is empty', async () => {
    const wrapper = mountPicker([])
    const btn = wrapper.find('button')
    expect((btn.element as HTMLButtonElement).disabled).toBe(true)
  })

  // DP-05: Confirm button enabled when at least one device selected
  it('confirm button is enabled when a device is selected', async () => {
    const wrapper = mountPicker([1])
    const btn = wrapper.find('button')
    expect((btn.element as HTMLButtonElement).disabled).toBe(false)
  })

  // DP-06: Device names are rendered
  it('renders all device names', () => {
    const wrapper = mountPicker([])
    expect(wrapper.text()).toContain('Living Room')
    expect(wrapper.text()).toContain('Bedroom')
  })

  // DP-07: Clicking the enabled confirm button emits 'confirm'
  it('emits confirm when the confirm button is clicked', async () => {
    const wrapper = mountPicker([1])
    await wrapper.find('button').trigger('click')
    expect(wrapper.emitted('confirm')).toBeTruthy()
  })

  // DP-08: Confirm label adapts to selection count (singular / plural / none)
  it('renders the singular confirm label for one selected device', () => {
    const wrapper = mountPicker([1])
    expect(wrapper.find('button').text()).toBe('Add to 1 frame')
  })

  it('renders the plural confirm label for multiple selected devices', () => {
    const wrapper = mountPicker([1, 2])
    expect(wrapper.find('button').text()).toBe('Add to 2 frames')
  })

  it('renders the no-selection confirm label when nothing is picked', () => {
    const wrapper = mountPicker([])
    expect(wrapper.find('button').text()).toBe('Add to frame')
  })

  // DP-09: Uploading state — label changes and button is disabled
  it('shows uploading label and disables the button while uploading', () => {
    const wrapper = mount(DevicePicker, {
      props: { modelValue: true, devices, selected: [1], uploading: true },
    })
    const btn = wrapper.find('button')
    expect(btn.text()).toBe('Uploading…')
    expect((btn.element as HTMLButtonElement).disabled).toBe(true)
  })

  // DP-10: Forwards update:modelValue from the wrapped sheet
  it('forwards update:modelValue from the wrapped sheet', async () => {
    const wrapper = mountPicker([])
    await wrapper.findComponent({ name: 'BaseBottomSheet' }).vm.$emit('update:modelValue', false)
    expect(wrapper.emitted('update:modelValue')).toEqual([[false]])
  })
})
