import { describe, it, expect } from 'vitest'
import {
  isPlainObject,
  defaultStructure,
  cloneStructure,
  computeStructureStats,
  formatStructurePreview,
} from '~/shared/model/componentStructure'
import {
  defaultPieceStructure,
  defaultProductStructure,
  clonePieceStructure,
  cloneProductStructure,
} from '~/shared/model/pieceProductStructure'

describe('isPlainObject', () => {
  it('returns true for plain objects', () => {
    expect(isPlainObject({})).toBe(true)
    expect(isPlainObject({ key: 'value' })).toBe(true)
  })

  it('returns false for arrays', () => {
    expect(isPlainObject([])).toBe(false)
  })

  it('returns false for null', () => {
    expect(isPlainObject(null)).toBe(false)
  })

  it('returns false for primitives', () => {
    expect(isPlainObject('string')).toBe(false)
    expect(isPlainObject(42)).toBe(false)
    expect(isPlainObject(undefined)).toBe(false)
  })
})

describe('defaultStructure', () => {
  it('returns a fresh empty structure each time', () => {
    const a = defaultStructure()
    const b = defaultStructure()
    expect(a).toEqual(b)
    expect(a).not.toBe(b)
    expect(a.customFields).toEqual([])
    expect(a.pieces).toEqual([])
    expect(a.products).toEqual([])
    expect(a.subcomponents).toEqual([])
  })
})

describe('cloneStructure', () => {
  it('deep clones a structure', () => {
    const original = defaultStructure()
    original.customFields.push({ name: 'test', type: 'text', required: false })
    const cloned = cloneStructure(original)
    expect(cloned.customFields).toHaveLength(1)
    expect(cloned.customFields[0].name).toBe('test')
    // Ensure deep clone — mutating original doesn't affect clone
    original.customFields[0].name = 'mutated'
    expect(cloned.customFields[0].name).toBe('test')
  })

  it('returns default structure for null input', () => {
    const result = cloneStructure(null)
    expect(result).toEqual(defaultStructure())
  })

  it('returns default structure for undefined input', () => {
    const result = cloneStructure(undefined)
    expect(result).toEqual(defaultStructure())
  })

  it('preserves typeComposantId and alias', () => {
    const input = {
      ...defaultStructure(),
      typeComposantId: 'abc-123',
      alias: 'Motor',
    }
    const result = cloneStructure(input)
    expect(result.typeComposantId).toBe('abc-123')
    expect(result.alias).toBe('Motor')
  })
})

describe('computeStructureStats', () => {
  it('counts elements in a structure', () => {
    const structure = {
      ...defaultStructure(),
      customFields: [
        { name: 'A', type: 'text' as const, required: false },
        { name: 'B', type: 'number' as const, required: true },
      ],
      pieces: [{ typePieceId: 'p1' }],
      products: [{ typeProductId: 'pr1' }],
      subcomponents: [{ subcomponents: [] }],
    }
    const stats = computeStructureStats(structure)
    expect(stats.customFields).toBe(2)
    expect(stats.pieces).toBe(1)
    expect(stats.products).toBe(1)
    expect(stats.subcomponents).toBe(1)
  })

  it('returns zeros for empty structure', () => {
    const stats = computeStructureStats(defaultStructure())
    expect(stats).toEqual({
      customFields: 0,
      pieces: 0,
      products: 0,
      subcomponents: 0,
    })
  })
})

describe('formatStructurePreview', () => {
  it('returns "Structure vide" for empty structure', () => {
    const result = formatStructurePreview(defaultStructure())
    expect(result).toBe('Structure vide')
  })

  it('formats a non-empty structure', () => {
    const structure = {
      ...defaultStructure(),
      customFields: [{ name: 'A', type: 'text' as const, required: false }],
      pieces: [{ typePieceId: 'p1' }, { typePieceId: 'p2' }],
    }
    const result = formatStructurePreview(structure)
    expect(result).toContain('1 champ')
    expect(result).toContain('2 pièce')
  })
})

describe('defaultPieceStructure', () => {
  it('returns a valid empty piece structure', () => {
    const result = defaultPieceStructure()
    expect(result.customFields).toEqual([])
    expect(result.products).toEqual([])
  })
})

describe('defaultProductStructure', () => {
  it('returns a valid empty product structure', () => {
    const result = defaultProductStructure()
    expect(result.customFields).toEqual([])
  })
})

describe('clonePieceStructure', () => {
  it('deep clones a piece structure', () => {
    const original = defaultPieceStructure()
    original.customFields.push({ name: 'Weight', type: 'number', required: true })
    const cloned = clonePieceStructure(original)
    expect(cloned.customFields).toHaveLength(1)
    original.customFields[0].name = 'mutated'
    expect(cloned.customFields[0].name).toBe('Weight')
  })

  it('returns default for null', () => {
    expect(clonePieceStructure(null)).toEqual(defaultPieceStructure())
  })
})

describe('cloneProductStructure', () => {
  it('deep clones a product structure', () => {
    const original = defaultProductStructure()
    original.customFields.push({ name: 'Color', type: 'text', required: false })
    const cloned = cloneProductStructure(original)
    expect(cloned.customFields).toHaveLength(1)
  })
})
