import { describe, it, expect } from 'vitest'
// @ts-expect-error — plain JS ESM audit script, no types
import { findOverlaps, bboxOverlap, collectContainers } from '../scripts/audit-mockup-overlap.mjs'

const box = (x: number, y: number, w: number, h: number) => ({ x, y, width: w, height: h })
function block(id: string, type: string, b: any, extra: any = {}) {
  return { id, type, name: id, absoluteBoundingBox: b, ...extra }
}
function section(id: string, children: any[]) {
  return { id, type: 'SECTION', name: id, children }
}
function page(children: any[]) {
  return { id: 'page', type: 'CANVAS', name: 'Page 1', children }
}

describe('bboxOverlap', () => {
  it('detects overlap > tolerance in both axes', () => {
    expect(bboxOverlap(box(0, 0, 100, 100), box(50, 50, 100, 100))).toEqual({ w: 50, h: 50 })
  })
  it('ignores sub-pixel touching (≤1px)', () => {
    expect(bboxOverlap(box(0, 0, 100, 100), box(100.4, 0, 100, 100))).toBeNull()
    expect(bboxOverlap(box(0, 0, 100, 100), box(99.5, 0, 100, 100))).toBeNull() // 0.5 overlap < tol
  })
})

describe('findOverlaps — §M-INTEGRITY sibling-block-overlap', () => {
  it('FLAGS two overlapping cards inside a SECTION', () => {
    const sec = section('S', [
      block('cardA', 'FRAME', box(0, 0, 200, 100)),
      block('cardB', 'FRAME', box(0, 80, 200, 100)),
    ])
    const r = findOverlaps(page([sec]))
    expect(r.length).toBe(1)
    expect([r[0].aId, r[0].bId].sort()).toEqual(['cardA', 'cardB'])
  })

  it('PASSES non-overlapping tiled cards', () => {
    const sec = section('S', [
      block('cardA', 'FRAME', box(0, 0, 200, 100)),
      block('cardB', 'FRAME', box(0, 120, 200, 100)),
    ])
    expect(findOverlaps(page([sec]))).toEqual([])
  })

  it('does NOT descend into a product FRAME (internal layering allowed)', () => {
    // a product device frame whose children intentionally overlap (z-stack)
    const device = block('device', 'FRAME', box(0, 0, 400, 800), {
      children: [
        block('bg', 'RECTANGLE', box(0, 0, 400, 800)),
        block('overlay', 'FRAME', box(50, 50, 100, 100)),
        block('overlay2', 'FRAME', box(60, 60, 100, 100)), // overlaps overlay — but internal, not checked
      ],
    })
    const sec = section('S', [device])
    expect(findOverlaps(page([sec]))).toEqual([])
  })

  it('excludes RECTANGLE/VECTOR (backing & connectors) from comparison', () => {
    const sec = section('S', [
      block('card', 'FRAME', box(0, 0, 200, 100)),
      block('backing', 'RECTANGLE', box(0, 0, 200, 100)), // backing behind card — excluded
      block('connector', 'VECTOR', box(10, 10, 50, 50)), // connector over card — excluded
    ])
    expect(findOverlaps(page([sec]))).toEqual([])
  })

  it('ignores invisible blocks', () => {
    const sec = section('S', [
      block('cardA', 'FRAME', box(0, 0, 200, 100)),
      block('cardB', 'FRAME', box(0, 80, 200, 100), { visible: false }),
    ])
    expect(findOverlaps(page([sec]))).toEqual([])
  })

  it('checks page (CANVAS) direct children too', () => {
    const r = findOverlaps(page([
      block('topA', 'FRAME', box(0, 0, 300, 300)),
      block('topB', 'INSTANCE', box(100, 100, 300, 300)),
    ]))
    expect(r.length).toBe(1)
  })

  it('collectContainers includes nested sections and the root', () => {
    const inner = section('inner', [])
    const root = section('root', [inner])
    const ids = collectContainers(root).map((c: any) => c.id).sort()
    expect(ids).toEqual(['inner', 'root'])
  })
})
