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

// Mock vue-konva to avoid canvas issues if transitively imported
vi.mock('vue-konva', () => ({}))

const defaultProps = {
  deviceId: 1,
  name: 'Living Room',
  size: 'large' as const,
  status: 'ok' as const,
  orientation: 'landscape' as const,
}

describe('FrameCard', () => {
  it('renders device name', () => {
    const wrapper = mount(FrameCard, { props: defaultProps })
    expect(wrapper.text()).toContain('Living Room')
  })

  it('shows "Online" status when status is ok', () => {
    const wrapper = mount(FrameCard, { props: defaultProps })
    expect(wrapper.find('.frame-card__status-line').text()).toContain('Online')
  })

  it('shows "Offline" status when status is offline', () => {
    const wrapper = mount(FrameCard, {
      props: { ...defaultProps, status: 'offline' },
    })
    expect(wrapper.find('.frame-card__status-line').text()).toContain('Offline')
  })

  it('shows "Sync issue" status when status is sync-fail', () => {
    const wrapper = mount(FrameCard, {
      props: { ...defaultProps, status: 'sync-fail' },
    })
    expect(wrapper.find('.frame-card__status-line').text()).toContain('Sync issue')
  })

  it('renders lastSync and nextSync lines on the large card', () => {
    const wrapper = mount(FrameCard, {
      props: { ...defaultProps, lastSync: '2h ago', nextSync: 'next sync in 4h' },
    })
    const sync = wrapper.find('.frame-card__sync-line')
    expect(sync.exists()).toBe(true)
    expect(sync.text()).toContain('synced 2h ago')
    expect(sync.text()).toContain('next sync in 4h')
  })

  it('omits the sync line on the large card when no sync info is provided', () => {
    const wrapper = mount(FrameCard, { props: defaultProps })
    expect(wrapper.find('.frame-card__sync-line').exists()).toBe(false)
  })

  // Cover the lastSync-without-nextSync branch: only the "synced X ago" span
  // renders, no separator, no nextSync.
  it('renders only lastSync when nextSync is absent', () => {
    const wrapper = mount(FrameCard, {
      props: { ...defaultProps, lastSync: '5m ago' },
    })
    const sync = wrapper.find('.frame-card__sync-line')
    expect(sync.text()).toContain('synced 5m ago')
    expect(sync.find('.frame-card__sync-sep').exists()).toBe(false)
  })

  // Inverse: nextSync without lastSync (a never-seen device that already has
  // wakeTimes configured — the card should still preview the next slot).
  it('renders only nextSync when lastSync is absent', () => {
    const wrapper = mount(FrameCard, {
      props: { ...defaultProps, nextSync: 'next sync ~6 AM tomorrow' },
    })
    const sync = wrapper.find('.frame-card__sync-line')
    expect(sync.exists()).toBe(true)
    expect(sync.text()).toContain('next sync ~6 AM tomorrow')
    expect(sync.text()).not.toContain('synced')
  })

  it('applies offline modifier class when status is offline', () => {
    const wrapper = mount(FrameCard, {
      props: { ...defaultProps, status: 'offline' },
    })
    expect(wrapper.classes()).toContain('frame-card--offline')
  })

  it('applies sync-fail modifier class when status is sync-fail', () => {
    const wrapper = mount(FrameCard, {
      props: { ...defaultProps, status: 'sync-fail' },
    })
    expect(wrapper.classes()).toContain('frame-card--sync-fail')
  })

  it('shows settings button in large size', () => {
    const wrapper = mount(FrameCard, { props: { ...defaultProps, size: 'large' } })
    expect(wrapper.find('.frame-card__settings-btn').exists()).toBe(true)
  })

  it('does not show settings button in compact size', () => {
    const wrapper = mount(FrameCard, {
      props: { ...defaultProps, size: 'compact' },
    })
    expect(wrapper.find('.frame-card__settings-btn').exists()).toBe(false)
  })

  it('shows img element when thumbnailUrl is provided', () => {
    const wrapper = mount(FrameCard, {
      props: { ...defaultProps, thumbnailUrl: '/thumb/test.jpg' },
    })
    const img = wrapper.find('img.frame-card__img')
    expect(img.exists()).toBe(true)
    expect(img.attributes('src')).toBe('/thumb/test.jpg')
  })

  it('shows empty preview placeholder when no thumbnailUrl', () => {
    const wrapper = mount(FrameCard, { props: defaultProps })
    expect(wrapper.find('.frame-card__empty-preview').exists()).toBe(true)
    expect(wrapper.find('img.frame-card__img').exists()).toBe(false)
  })

  it('shows photo count in compact size', () => {
    const wrapper = mount(FrameCard, {
      props: { ...defaultProps, size: 'compact', photoCount: 3 },
    })
    expect(wrapper.text()).toContain('3 photos')
  })

  it('uses singular "photo" when photoCount is 1', () => {
    const wrapper = mount(FrameCard, {
      props: { ...defaultProps, size: 'compact', photoCount: 1 },
    })
    expect(wrapper.text()).toContain('1 photo')
    expect(wrapper.text()).not.toContain('1 photos')
  })

  it('emits add-photo with deviceId when add button clicked', async () => {
    const wrapper = mount(FrameCard, { props: defaultProps })
    await wrapper.find('.frame-card__add-btn').trigger('click')
    expect(wrapper.emitted('add-photo')).toBeTruthy()
    expect(wrapper.emitted('add-photo')![0]).toEqual([1])
  })

  it('emits edit with deviceId when settings button clicked (large)', async () => {
    const wrapper = mount(FrameCard, { props: { ...defaultProps, size: 'large' } })
    await wrapper.find('.frame-card__settings-btn').trigger('click')
    expect(wrapper.emitted('edit')).toBeTruthy()
    expect(wrapper.emitted('edit')![0]).toEqual([1])
  })

  // Aspect ratio is set on the preview container itself (not the placeholder)
  // so the box shape is stable whether or not the thumbnail has loaded —
  // image inside scales with object-fit: contain.
  it('locks preview aspect to V1 landscape (1600 × 960)', () => {
    const wrapper = mount(FrameCard, {
      props: { ...defaultProps, size: 'large', orientation: 'landscape', model: 'v1' },
    })
    expect(wrapper.find('.frame-card__preview').attributes('style')).toMatch(/aspect-ratio:\s*1600\s*\/\s*960/)
  })

  it('locks preview aspect to V1 portrait (960 × 1600)', () => {
    const wrapper = mount(FrameCard, {
      props: { ...defaultProps, size: 'large', orientation: 'portrait', model: 'v1' },
    })
    expect(wrapper.find('.frame-card__preview').attributes('style')).toMatch(/aspect-ratio:\s*960\s*\/\s*1600/)
  })

  it('locks preview aspect to V2 portrait (1200 × 1600)', () => {
    const wrapper = mount(FrameCard, {
      props: { ...defaultProps, size: 'large', orientation: 'portrait', model: 'v2' },
    })
    expect(wrapper.find('.frame-card__preview').attributes('style')).toMatch(/aspect-ratio:\s*1200\s*\/\s*1600/)
  })

  it('locks preview aspect to V2 landscape (1600 × 1200)', () => {
    const wrapper = mount(FrameCard, {
      props: { ...defaultProps, size: 'large', orientation: 'landscape', model: 'v2' },
    })
    expect(wrapper.find('.frame-card__preview').attributes('style')).toMatch(/aspect-ratio:\s*1600\s*\/\s*1200/)
  })
})
