// Pins the shared sizing math behind every "post-shaped" media slot:
//  - height derives from the intrinsic aspect (width / (w/h))
//  - missing server dimensions fall back to one documented aspect (4/3),
//    replacing FeedPost's old 430/500 pixel-height split
//  - maxHeight caps portrait media but never pads short media

import type { MediaAttachment } from 'src/lib/api-types'
import { getIntrinsicAspectRatio, mediaHeight } from 'src/lib/media-source'

function att(width?: number, height?: number): MediaAttachment {
  return {
    id: '1',
    type: 'image',
    url: 'https://cdn.example/a.jpg',
    preview_url: null,
    remote_url: null,
    meta:
      typeof width === 'number' && typeof height === 'number'
        ? ({ original: { width, height } } as MediaAttachment['meta'])
        : ({} as MediaAttachment['meta']),
    description: null,
    blurhash: null,
    text_url: undefined,
  } as MediaAttachment
}

describe('mediaHeight', () => {
  it('derives height from intrinsic aspect (square)', () => {
    expect(mediaHeight(att(1000, 1000), 400)).toBe(400)
  })

  it('derives height from intrinsic aspect (landscape)', () => {
    // 1600x900 → aspect 16/9 → 400 / (16/9) = 225
    expect(mediaHeight(att(1600, 900), 400)).toBe(225)
  })

  it('derives a taller box for portrait media', () => {
    // 900x1600 → aspect 9/16 → 400 / (9/16) = 711.11…
    expect(mediaHeight(att(900, 1600), 400)).toBeCloseTo(711.11, 1)
  })

  it('falls back to 4/3 when dimensions are missing', () => {
    // no meta → aspect 4/3 → 400 / (4/3) = 300
    expect(mediaHeight(att(), 400)).toBe(300)
    expect(mediaHeight(null, 400)).toBe(300)
    expect(mediaHeight(undefined, 400)).toBe(300)
  })

  it('honors a custom fallbackAspect', () => {
    // no meta, fallback 16/9 → 400 / (16/9) = 225
    expect(mediaHeight(att(), 400, { fallbackAspect: 16 / 9 })).toBe(225)
  })

  it('caps height at maxHeight for tall media', () => {
    // portrait would be 711 → capped to 500
    expect(mediaHeight(att(900, 1600), 400, { maxHeight: 500 })).toBe(500)
  })

  it('does not pad media shorter than maxHeight', () => {
    // landscape 225 < 500 cap → unchanged
    expect(mediaHeight(att(1600, 900), 400, { maxHeight: 500 })).toBe(225)
  })

  it('ignores zero/invalid dimensions and uses the fallback', () => {
    expect(mediaHeight(att(0, 0), 400)).toBe(300)
  })
})

// getIntrinsicAspectRatio is the `null`-or-number signal VideoPlayer keys on:
// a real ratio means "trust the server, don't measure the poster"; `null`
// means "dims missing — fall back to the measured poster aspect." A wrong
// `null`/number split is exactly what reintroduces the portrait-video side-bar
// bug, so pin both sides.
describe('getIntrinsicAspectRatio', () => {
  it('returns width/height when server dims are present', () => {
    expect(getIntrinsicAspectRatio(att(1600, 900))).toBeCloseTo(16 / 9, 5)
    expect(getIntrinsicAspectRatio(att(900, 1600))).toBeCloseTo(9 / 16, 5)
    expect(getIntrinsicAspectRatio(att(1000, 1000))).toBe(1)
  })

  it('returns null when dims are missing or invalid', () => {
    expect(getIntrinsicAspectRatio(att())).toBeNull()
    expect(getIntrinsicAspectRatio(att(0, 0))).toBeNull()
    expect(getIntrinsicAspectRatio(null)).toBeNull()
    expect(getIntrinsicAspectRatio(undefined)).toBeNull()
  })
})
