import { describe, it, expect, vi, beforeEach } from 'vitest'
import { mount, flushPromises } from '@vue/test-utils'
import { setActivePinia, createPinia } from 'pinia'
import ApproveCard from '@/components/ApproveCard.vue'
import { useImagesStore } from '@/stores/images'
import { useDevicesStore } from '@/stores/devices'
import type { SharedImage, Device } from '@/types'

vi.mock('@/components/DevicePicker.vue', () => ({
  default: {
    name: 'DevicePicker',
    template: '<div class="device-picker-stub"><slot /></div>',
    props: ['modelValue', 'devices', 'selected', 'uploading', 'confirmLabel'],
    emits: ['update:modelValue', 'update:selected', 'confirm'],
  },
}))
vi.mock('@/components/BaseButton.vue', () => ({
  default: {
    name: 'BaseButton',
    template: '<button :disabled="disabled" @click="$emit(\'click\')"><slot /></button>',
    props: ['variant', 'size', 'disabled'],
    emits: ['click'],
  },
}))

const makeShared = (overrides: Partial<SharedImage> = {}): SharedImage => ({
  id: 1,
  thumbnailUrl: '/t/1.jpg',
  sharedBy: 'alice@example.com',
  sharedAt: '2026-01-15T00:00:00Z',
  status: 'pending',
  ...overrides,
} as SharedImage)

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

describe('ApproveCard', () => {
  beforeEach(() => {
    setActivePinia(createPinia())
  })

  it('renders sharer email and a formatted date', () => {
    const wrapper = mount(ApproveCard, { props: { item: makeShared() } })
    expect(wrapper.text()).toContain('alice@example.com')
    // date is locale-formatted; just confirm the year shows up
    expect(wrapper.text()).toContain('2026')
  })

  it('shows "Add to frame" + "Decline" actions for a pending share', () => {
    const wrapper = mount(ApproveCard, { props: { item: makeShared({ status: 'pending' }) } })
    expect(wrapper.text()).toContain('Add to frame')
    expect(wrapper.text()).toContain('Decline')
  })

  it('shows "Remove" but no add action for an approved share', () => {
    const wrapper = mount(ApproveCard, { props: { item: makeShared({ status: 'approved' }) } })
    expect(wrapper.text()).not.toContain('Add to frame')
    expect(wrapper.text()).toContain('Remove')
  })

  it('shows "Add anyway" but no decline action for a declined share', () => {
    const wrapper = mount(ApproveCard, { props: { item: makeShared({ status: 'declined' }) } })
    expect(wrapper.text()).toContain('Add anyway')
    expect(wrapper.text()).not.toContain('Decline')
  })

  it('renders a status badge for non-pending shares', () => {
    const wrapper = mount(ApproveCard, { props: { item: makeShared({ status: 'approved' }) } })
    expect(wrapper.find('.approve-card__badge--approved').exists()).toBe(true)
  })

  it('does not render a status badge for pending shares', () => {
    const wrapper = mount(ApproveCard, { props: { item: makeShared({ status: 'pending' }) } })
    expect(wrapper.find('.approve-card__badge').exists()).toBe(false)
  })

  it('opens the device picker when the add button is clicked', async () => {
    const devices = useDevicesStore()
    devices.devices = [makeDevice()]
    const wrapper = mount(ApproveCard, { props: { item: makeShared() } })
    const addBtn = wrapper.findAll('button').find(b => b.text() === 'Add to frame')!
    await addBtn.trigger('click')
    const picker = wrapper.findComponent({ name: 'DevicePicker' })
    expect(picker.props('modelValue')).toBe(true)
  })

  it('calls approveShared and emits updated when picker confirms', async () => {
    const images = useImagesStore()
    const updated = makeShared({ status: 'approved' })
    vi.spyOn(images, 'approveShared').mockResolvedValue(updated)
    const devices = useDevicesStore()
    devices.devices = [makeDevice()]

    const wrapper = mount(ApproveCard, { props: { item: makeShared() } })
    await wrapper.findAll('button').find(b => b.text() === 'Add to frame')!.trigger('click')

    const picker = wrapper.findComponent({ name: 'DevicePicker' })
    await picker.vm.$emit('update:selected', [10])
    await picker.vm.$emit('confirm')
    await flushPromises()

    expect(images.approveShared).toHaveBeenCalledWith(1, [10])
    expect(wrapper.emitted('updated')).toEqual([[updated]])
  })

  it('forwards update:modelValue from the picker so it can be closed', async () => {
    const devices = useDevicesStore()
    devices.devices = [makeDevice()]
    const wrapper = mount(ApproveCard, { props: { item: makeShared() } })
    await wrapper.findAll('button').find(b => b.text() === 'Add to frame')!.trigger('click')
    const picker = wrapper.findComponent({ name: 'DevicePicker' })
    expect(picker.props('modelValue')).toBe(true)
    await picker.vm.$emit('update:modelValue', false)
    await wrapper.vm.$nextTick()
    expect(wrapper.findComponent({ name: 'DevicePicker' }).props('modelValue')).toBe(false)
  })

  it('calls declineShared and emits updated when decline is clicked', async () => {
    const images = useImagesStore()
    const updated = makeShared({ status: 'declined' })
    vi.spyOn(images, 'declineShared').mockResolvedValue(updated)

    const wrapper = mount(ApproveCard, { props: { item: makeShared() } })
    await wrapper.findAll('button').find(b => b.text() === 'Decline')!.trigger('click')
    await flushPromises()

    expect(images.declineShared).toHaveBeenCalledWith(1)
    expect(wrapper.emitted('updated')).toEqual([[updated]])
  })
})
