import { describe, expect, it } from 'vitest';

import cleanState from './cleanState';
import { StudioProjectState } from './fixStudioProjectState';
import { StudioTrack } from './fixTrack';

const createMinimalTrack = (id: string): StudioTrack => ({
  id,
  name: 'Track',
  height: 100,
  clips: [],
  clipCreationIntents: [],
  solo: false,
  mute: false,
  arm: false,
  amplitude: 1.0,
  balance: 0,
  color: '#FF0000',
  input: null,
  instrument: { type: 'song' },
  soloTakeLaneId: null,
  takeLanes: [],
  takeLanesExpanded: false,
  eq: {
    enabled: true,
    band1: {
      type: 'highpass',
      enabled: false,
      frequency: 60,
      gain: 0,
      q: 0.707,
    },
    band2: {
      type: 'lowshelf',
      enabled: true,
      frequency: 160,
      gain: 0,
      q: 0.707,
    },
    band3: {
      type: 'peaking',
      enabled: true,
      frequency: 450,
      gain: 0,
      q: 0.707,
    },
    band4: {
      type: 'peaking',
      enabled: true,
      frequency: 1200,
      gain: 0,
      q: 0.707,
    },
    band5: {
      type: 'highshelf',
      enabled: true,
      frequency: 3200,
      gain: 0,
      q: 0.707,
    },
    band6: {
      type: 'lowpass',
      enabled: false,
      frequency: 8800,
      gain: 0,
      q: 0.707,
    },
  },
});

describe('cleanState', () => {
  it('should filter undefined tracks', () => {
    const state = {
      tracks: [
        createMinimalTrack('track1'),
        undefined as any,
        createMinimalTrack('track2'),
      ],
    };

    const result = cleanState(state as unknown as StudioProjectState);

    expect(result.tracks).toHaveLength(2);
    expect(result.tracks[0].id).toBe('track1');
    expect(result.tracks[1].id).toBe('track2');
  });

  it('should maintain referential stability', () => {
    const state = {
      tracks: [createMinimalTrack('track1')],
      otherField: 'test',
    };

    const result = cleanState(state as unknown as StudioProjectState);

    expect(result).toBe(state);
    expect((result as unknown as { otherField: string }).otherField).toBe(
      'test'
    );
  });

  it('should maintain referential stability for clips arrays', () => {
    const track = createMinimalTrack('track1');
    const clipsArray = [] as any[];
    track.clips = clipsArray;

    const state = { tracks: [track] };
    const result = cleanState(state as unknown as StudioProjectState);

    expect(result.tracks[0].clips).toBe(clipsArray);
  });

  it('should sort clipCreationIntents by startBeats and endBeats', () => {
    const track = createMinimalTrack('track1');
    track.clipCreationIntents = [
      {
        id: 'intent3',
        possibleClipIds: ['c3'],
        queuedGenerationIds: [],
        name: 'Intent 3',
        namePersists: false,
        startBeats: 4,
        endBeats: 12,
        startTrimmedBeats: 0,
        endTrimmedBeats: 0,
      },
      {
        id: 'intent1',
        possibleClipIds: ['c1'],
        queuedGenerationIds: [],
        name: 'Intent 1',
        namePersists: false,
        startBeats: 0,
        endBeats: 4,
        startTrimmedBeats: 0,
        endTrimmedBeats: 0,
      },
      {
        id: 'intent2',
        possibleClipIds: ['c2'],
        queuedGenerationIds: [],
        name: 'Intent 2',
        namePersists: false,
        startBeats: 0,
        endBeats: 8,
        startTrimmedBeats: 0,
        endTrimmedBeats: 0,
      },
    ];

    const state = { tracks: [track] };
    const result = cleanState(state as unknown as StudioProjectState);

    expect(result.tracks[0].clipCreationIntents.map((c) => c.id)).toEqual([
      'intent1',
      'intent2',
      'intent3',
    ]);
  });

  it('should process take lanes clipCreationIntents', () => {
    const track = createMinimalTrack('track1');
    const takeLane = createMinimalTrack('takeLane1');
    takeLane.clipCreationIntents = [
      {
        id: 'intent2',
        possibleClipIds: ['c2'],
        queuedGenerationIds: [],
        name: 'Intent 2',
        namePersists: false,
        startBeats: 4,
        startTrimmedBeats: 0,
        endTrimmedBeats: 0,
      },
      {
        id: 'intent1',
        possibleClipIds: ['c1'],
        queuedGenerationIds: [],
        name: 'Intent 1',
        namePersists: false,
        startBeats: 0,
        startTrimmedBeats: 0,
        endTrimmedBeats: 0,
      },
    ];
    track.takeLanes = [takeLane];

    const state = { tracks: [track] };
    const result = cleanState(state as unknown as StudioProjectState);

    // Take lane intents should be sorted
    expect(
      result.tracks[0].takeLanes[0].clipCreationIntents.map((c) => c.id)
    ).toEqual(['intent1', 'intent2']);
  });
});
