import { describe, it, expect } from 'vitest'
import { sortLayers } from './sort-layers'
import { MAP_MEASURE_LAYER_ID } from '../editable/measurement-tools/const'
import {
  MAP_LASSO_TOOLS_LAYER_ID,
  MAP_MASK_LAYER_ID,
} from '../editable/lasso-tools/const'
import type { Layer } from '../providers/layers/types'
import { GeoJsonLayer } from '@deck.gl/layers'

describe('sortLayers', () => {
  it('should sort layers by order property', () => {
    const layers: Layer[] = [
      { props: { id: 'layer3' }, order: 3, type: GeoJsonLayer },
      { props: { id: 'layer1' }, order: 1, type: GeoJsonLayer },
      { props: { id: 'layer2' }, order: 2, type: GeoJsonLayer },
    ]

    const result = sortLayers(layers)

    expect(result[0]?.props.id).toBe('layer1')
    expect(result[1]?.props.id).toBe('layer2')
    expect(result[2]?.props.id).toBe('layer3')
  })

  it('should place mask layer at the end', () => {
    const layers: Layer[] = [
      { props: { id: MAP_MASK_LAYER_ID }, order: 1, type: GeoJsonLayer },
      { props: { id: 'layer1' }, order: 2, type: GeoJsonLayer },
      { props: { id: 'layer2' }, order: 3, type: GeoJsonLayer },
    ]

    const result = sortLayers(layers)

    expect(result[result.length - 1]?.props.id).toBe(MAP_MASK_LAYER_ID)
  })

  it('should place lasso tools layer at the end', () => {
    const layers: Layer[] = [
      { props: { id: 'layer1' }, order: 1, type: GeoJsonLayer },
      { props: { id: MAP_LASSO_TOOLS_LAYER_ID }, order: 2, type: GeoJsonLayer },
      { props: { id: 'layer2' }, order: 3, type: GeoJsonLayer },
    ]

    const result = sortLayers(layers)

    expect(result[result.length - 1]?.props.id).toBe(MAP_LASSO_TOOLS_LAYER_ID)
  })

  it('should place measurement layer at the end', () => {
    const layers: Layer[] = [
      { props: { id: 'layer1' }, order: 1, type: GeoJsonLayer },
      { props: { id: 'layer2' }, order: 2, type: GeoJsonLayer },
      { props: { id: MAP_MEASURE_LAYER_ID }, order: 3, type: GeoJsonLayer },
    ]

    const result = sortLayers(layers)

    expect(result[result.length - 1]?.props.id).toBe(MAP_MEASURE_LAYER_ID)
  })

  it('should maintain correct order of special layers at end', () => {
    const layers: Layer[] = [
      { props: { id: 'layer1' }, order: 1, type: GeoJsonLayer },
      { props: { id: MAP_MEASURE_LAYER_ID }, type: GeoJsonLayer },
      { props: { id: MAP_LASSO_TOOLS_LAYER_ID }, type: GeoJsonLayer },
      { props: { id: MAP_MASK_LAYER_ID }, type: GeoJsonLayer },
      { props: { id: 'layer2' }, order: 2, type: GeoJsonLayer },
    ]

    const result = sortLayers(layers)

    // Regular layers sorted by order first
    expect(result[0]?.props.id).toBe('layer1')
    expect(result[1]?.props.id).toBe('layer2')

    // Special layers at the end in specific order: mask, lasso, measure
    expect(result[2]?.props.id).toBe(MAP_MASK_LAYER_ID)
    expect(result[3]?.props.id).toBe(MAP_LASSO_TOOLS_LAYER_ID)
    expect(result[4]?.props.id).toBe(MAP_MEASURE_LAYER_ID)
  })

  it('should handle layers without order property', () => {
    const layers: Layer[] = [
      { props: { id: 'layer1' }, order: 1, type: GeoJsonLayer },
      { props: { id: 'layer-no-order' }, type: GeoJsonLayer },
      { props: { id: 'layer2' }, order: 2, type: GeoJsonLayer },
    ]

    const result = sortLayers(layers)

    // Layer without order goes last (before special layers)
    expect(result[0]?.props.id).toBe('layer1')
    expect(result[1]?.props.id).toBe('layer2')
    expect(result[2]?.props.id).toBe('layer-no-order')
  })

  it('should handle empty array', () => {
    const layers: Layer[] = []
    const result = sortLayers(layers)
    expect(result).toEqual([])
  })

  it('should handle array with only special layers', () => {
    const layers: Layer[] = [
      { props: { id: MAP_MEASURE_LAYER_ID }, type: GeoJsonLayer },
      { props: { id: MAP_MASK_LAYER_ID }, type: GeoJsonLayer },
    ]

    const result = sortLayers(layers)

    expect(result).toHaveLength(2)
    expect(result[0]?.props.id).toBe(MAP_MASK_LAYER_ID)
    expect(result[1]?.props.id).toBe(MAP_MEASURE_LAYER_ID)
  })

  it('should handle layers with duplicate order values', () => {
    const layers: Layer[] = [
      { props: { id: 'layer1' }, order: 1, type: GeoJsonLayer },
      { props: { id: 'layer2' }, order: 1, type: GeoJsonLayer },
      { props: { id: 'layer3' }, order: 2, type: GeoJsonLayer },
    ]

    const result = sortLayers(layers)

    // Should maintain stable sort
    expect(result).toHaveLength(3)
    expect(result[2]?.props.id).toBe('layer3')
  })

  it('should handle negative order values', () => {
    const layers: Layer[] = [
      { props: { id: 'layer1' }, order: -1, type: GeoJsonLayer },
      { props: { id: 'layer2' }, order: 0, type: GeoJsonLayer },
      { props: { id: 'layer3' }, order: 1, type: GeoJsonLayer },
    ]

    const result = sortLayers(layers)

    expect(result[0]?.props.id).toBe('layer1')
    expect(result[1]?.props.id).toBe('layer2')
    expect(result[2]?.props.id).toBe('layer3')
  })

  it('should handle large order values', () => {
    const layers: Layer[] = [
      { props: { id: 'layer1' }, order: 1000000, type: GeoJsonLayer },
      { props: { id: 'layer2' }, order: 1, type: GeoJsonLayer },
      { props: { id: 'layer3' }, order: 500, type: GeoJsonLayer },
    ]

    const result = sortLayers(layers)

    expect(result[0]?.props.id).toBe('layer2')
    expect(result[1]?.props.id).toBe('layer3')
    expect(result[2]?.props.id).toBe('layer1')
  })

  it('should handle mixed regular and special layers', () => {
    const layers: Layer[] = [
      { props: { id: 'regular1' }, order: 1, type: GeoJsonLayer },
      { props: { id: MAP_MASK_LAYER_ID }, type: GeoJsonLayer },
      { props: { id: 'regular2' }, order: 2, type: GeoJsonLayer },
      { props: { id: MAP_LASSO_TOOLS_LAYER_ID }, type: GeoJsonLayer },
      { props: { id: 'regular3' }, order: 3, type: GeoJsonLayer },
      { props: { id: MAP_MEASURE_LAYER_ID }, type: GeoJsonLayer },
    ]

    const result = sortLayers(layers)

    expect(result).toHaveLength(6)
    // Regular layers first, sorted by order
    expect(result[0]?.props.id).toBe('regular1')
    expect(result[1]?.props.id).toBe('regular2')
    expect(result[2]?.props.id).toBe('regular3')
    // Special layers last in specific order
    expect(result[3]?.props.id).toBe(MAP_MASK_LAYER_ID)
    expect(result[4]?.props.id).toBe(MAP_LASSO_TOOLS_LAYER_ID)
    expect(result[5]?.props.id).toBe(MAP_MEASURE_LAYER_ID)
  })
})
