// @vitest-environment node
import { describe, expect, it } from 'vitest';

import { TEST_CLIP } from '@/components/clipBrowser/__tests__/fixtures/clips';
import { Clip } from '@/state/clipStore';

import {
  PartialClip,
  clipEditsDisableVolumeNormalization,
  formatClipPrompt,
  formatClipTitle,
  getClipDisplayTags,
  getClipFullTags,
  getClipFullTagsString,
  getClipTitle,
  getExtendTask,
  isComplete,
  isStemClip,
  isUnpublishableUploadClip,
  isValidModelVersion,
  shouldShowGetFullSong,
} from './clip';

describe('clip utils', () => {
  describe('isUnpublishableUploadClip', () => {
    it('should return false when clip has no vocals', () => {
      const clip: Clip = {
        ...TEST_CLIP,
        metadata: { ...TEST_CLIP.metadata, has_vocal: false },
      };
      expect(isUnpublishableUploadClip(clip)).toBe(false);
    });

    it('should return false when clip can publish with vocals', () => {
      const clip: Clip = {
        ...TEST_CLIP,
        metadata: {
          ...TEST_CLIP.metadata,
          has_vocal: true,
          can_publish_with_vocal: true,
        },
      };
      expect(isUnpublishableUploadClip(clip)).toBe(false);
    });

    it('should return true when clip has vocals but cannot publish', () => {
      const clip: Clip = {
        ...TEST_CLIP,
        metadata: {
          ...TEST_CLIP.metadata,
          has_vocal: true,
          can_publish_with_vocal: false,
        },
      };
      expect(isUnpublishableUploadClip(clip)).toBe(true);
    });
  });

  describe('isStemClip', () => {
    it('should return true for stem clips', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        metadata: { ...TEST_CLIP.metadata, type: 'stem' },
      };
      expect(isStemClip(clip)).toBe(true);
    });

    it('should return false for non-stem clips', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        metadata: { ...TEST_CLIP.metadata, type: 'upload' },
      };
      expect(isStemClip(clip)).toBe(false);
    });

    it('should return false for null clip', () => {
      expect(isStemClip(null)).toBe(false);
    });

    it('should return false for clip without metadata', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        metadata: {},
      };
      expect(isStemClip(clip)).toBe(false);
    });
  });

  describe('isValidModelVersion', () => {
    it('should return true for v2 model', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        major_model_version: 'v2',
      };
      expect(isValidModelVersion(clip)).toBe(true);
    });

    it('should return true for v3 model', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        major_model_version: 'v3',
      };
      expect(isValidModelVersion(clip)).toBe(true);
    });

    it('should return true for v3.5 model', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        major_model_version: 'v3.5',
      };
      expect(isValidModelVersion(clip)).toBe(true);
    });

    it('should return true for v4 model', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        major_model_version: 'v4',
      };
      expect(isValidModelVersion(clip)).toBe(true);
    });

    it('should return true for v4.5 model', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        major_model_version: 'v4.5',
      };
      expect(isValidModelVersion(clip)).toBe(true);
    });

    it('should return true for auk model', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        model_name: 'chirp-v3-auk',
      };
      expect(isValidModelVersion(clip)).toBe(true);
    });

    it('should return true for bluejay model', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        model_name: 'chirp-v3-bluejay',
      };
      expect(isValidModelVersion(clip)).toBe(true);
    });

    it('should return true for crow model', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        model_name: 'chirp-v3-crow',
      };
      expect(isValidModelVersion(clip)).toBe(true);
    });

    it('should return true for upload type', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        metadata: { ...TEST_CLIP.metadata, type: 'upload' },
      };
      expect(isValidModelVersion(clip)).toBe(true);
    });

    it('should return true for edit_crop type', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        metadata: { ...TEST_CLIP.metadata, type: 'edit_crop' },
      };
      expect(isValidModelVersion(clip)).toBe(true);
    });

    it('should return true for edit_fade type', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        metadata: { ...TEST_CLIP.metadata, type: 'edit_fade' },
      };
      expect(isValidModelVersion(clip)).toBe(true);
    });

    it('should return true for edit_v3_export type', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        metadata: { ...TEST_CLIP.metadata, type: 'edit_v3_export' },
      };
      expect(isValidModelVersion(clip)).toBe(true);
    });

    it('should return false for invalid model', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        major_model_version: 'v1',
      };
      expect(isValidModelVersion(clip)).toBe(false);
    });

    it('should return false for null clip', () => {
      expect(isValidModelVersion(null)).toBe(false);
    });
  });

  describe('isComplete', () => {
    it('should return true for complete clips', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        status: 'complete',
      };
      expect(isComplete(clip)).toBe(true);
    });

    it('should return false for incomplete clips', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        status: 'processing',
      };
      expect(isComplete(clip)).toBe(false);
    });

    it('should return false for null clip', () => {
      expect(isComplete(null)).toBe(false);
    });
  });

  describe('shouldShowGetFullSong', () => {
    const validClip: PartialClip = {
      ...TEST_CLIP,
      major_model_version: 'v4',
      user_id: 'user123',
      metadata: {
        ...TEST_CLIP.metadata,
        history: ['parent-1'],
        infill: false,
        type: 'gen',
      },
    };

    it('should return true for valid clip owned by user', () => {
      expect(shouldShowGetFullSong(validClip, 'user123')).toBe(true);
    });

    it('should return false when user is not the owner', () => {
      expect(shouldShowGetFullSong(validClip, 'otherUser')).toBe(false);
    });

    it('should return false for invalid model version', () => {
      const clip: PartialClip = {
        ...validClip,
        major_model_version: 'v1',
      };
      expect(shouldShowGetFullSong(clip, 'user123')).toBe(false);
    });

    it('should return false when clip has no history', () => {
      const clip: PartialClip = {
        ...validClip,
        metadata: { ...validClip.metadata, history: null },
      };
      expect(shouldShowGetFullSong(clip, 'user123')).toBe(false);
    });

    it('should return false for infill clips', () => {
      const clip: PartialClip = {
        ...validClip,
        metadata: { ...validClip.metadata, infill: true },
      };
      expect(shouldShowGetFullSong(clip, 'user123')).toBe(false);
    });

    it('should return false for stem clips', () => {
      const clip: PartialClip = {
        ...validClip,
        metadata: { ...validClip.metadata, type: 'stem' },
      };
      expect(shouldShowGetFullSong(clip, 'user123')).toBe(false);
    });

    it('should return false for null clip', () => {
      expect(shouldShowGetFullSong(null, 'user123')).toBe(false);
    });
  });

  describe('formatClipPrompt', () => {
    it('should remove bracketed text', () => {
      const prompt = 'This is a [Verse] test prompt';
      expect(formatClipPrompt(prompt)).toBe('This is a  test prompt');
    });

    it('should trim whitespace', () => {
      const prompt = '  test prompt  ';
      expect(formatClipPrompt(prompt)).toBe('test prompt');
    });

    it('should take only the first line', () => {
      const prompt = 'First line\nSecond line\nThird line';
      expect(formatClipPrompt(prompt)).toBe('First line');
    });

    it('should truncate to max length', () => {
      const prompt = 'This is a very long prompt that should be truncated';
      expect(formatClipPrompt(prompt, 20)).toBe('This is a very long ');
    });

    it('should handle multiple brackets', () => {
      const prompt = '[Intro] Test [Verse] Another [Chorus] End';
      expect(formatClipPrompt(prompt)).toBe('Test  Another  End');
    });

    it('should use default max length of 40', () => {
      const prompt = 'a'.repeat(100);
      expect(formatClipPrompt(prompt)).toBe('a'.repeat(40));
    });
  });

  describe('formatClipTitle', () => {
    it('should return title when provided', () => {
      expect(formatClipTitle('My Title', 'prompt text')).toBe('My Title');
    });

    it('should return formatted prompt when no title', () => {
      expect(formatClipTitle(null, 'This is a [Verse] prompt')).toBe(
        'This is a  prompt'
      );
    });

    it('should return fallback when no title or prompt', () => {
      expect(formatClipTitle(null, null)).toBe('Untitled');
    });

    it('should return custom fallback', () => {
      expect(formatClipTitle(null, null, 'Custom Fallback')).toBe(
        'Custom Fallback'
      );
    });

    it('should return formatted prompt when title is empty string', () => {
      expect(formatClipTitle('', 'prompt text')).toBe('prompt text');
    });

    it('should return fallback when prompt is empty string', () => {
      expect(formatClipTitle(null, '')).toBe('Untitled');
    });
  });

  describe('getClipTitle', () => {
    it('should return clip title when available', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        title: 'My Song',
      };
      expect(getClipTitle(clip)).toBe('My Song');
    });

    it('should return formatted prompt when no title', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        title: null,
        metadata: { ...TEST_CLIP.metadata, prompt: '[Verse] Test prompt' },
      };
      expect(getClipTitle(clip)).toBe('Test prompt');
    });

    it('should return "Untitled" when no title or prompt', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        title: null,
        metadata: {},
      };
      expect(getClipTitle(clip)).toBe('Untitled');
    });

    it('should return "Untitled" for null clip', () => {
      expect(getClipTitle(null)).toBe('Untitled');
    });

    it('should return "Untitled" for undefined clip', () => {
      expect(getClipTitle(undefined)).toBe('Untitled');
    });
  });

  describe('getExtendTask', () => {
    it('should return "upload_extend" for upload clips', () => {
      const clip: Clip = {
        ...TEST_CLIP,
        metadata: { ...TEST_CLIP.metadata, type: 'upload' },
      };
      expect(getExtendTask(clip)).toBe('upload_extend');
    });

    it('should return "extend" for non-upload clips', () => {
      const clip: Clip = {
        ...TEST_CLIP,
        metadata: { ...TEST_CLIP.metadata, type: 'gen' },
      };
      expect(getExtendTask(clip)).toBe('extend');
    });
  });

  describe('clipEditsDisableVolumeNormalization', () => {
    it('should return true for upload type', () => {
      const clip: Clip = {
        ...TEST_CLIP,
        metadata: { ...TEST_CLIP.metadata, type: 'upload' },
      };
      expect(clipEditsDisableVolumeNormalization(clip)).toBe(true);
    });

    it('should return true for upload_extend type', () => {
      const clip: Clip = {
        ...TEST_CLIP,
        metadata: { ...TEST_CLIP.metadata, type: 'upload_extend' },
      };
      expect(clipEditsDisableVolumeNormalization(clip)).toBe(true);
    });

    it('should return true for rendered_context_window type', () => {
      const clip: Clip = {
        ...TEST_CLIP,
        metadata: { ...TEST_CLIP.metadata, type: 'rendered_context_window' },
      };
      expect(clipEditsDisableVolumeNormalization(clip)).toBe(true);
    });

    it('should return true for studio_export type', () => {
      const clip: Clip = {
        ...TEST_CLIP,
        metadata: { ...TEST_CLIP.metadata, type: 'studio_export' },
      };
      expect(clipEditsDisableVolumeNormalization(clip)).toBe(true);
    });

    it('should return true for edit_v3_export type', () => {
      const clip: Clip = {
        ...TEST_CLIP,
        metadata: { ...TEST_CLIP.metadata, type: 'edit_v3_export' },
      };
      expect(clipEditsDisableVolumeNormalization(clip)).toBe(true);
    });

    it('should return false for other types', () => {
      const clip: Clip = {
        ...TEST_CLIP,
        metadata: { ...TEST_CLIP.metadata, type: 'gen' },
      };
      expect(clipEditsDisableVolumeNormalization(clip)).toBe(false);
    });

    it('should return false when type is undefined', () => {
      const clip: Clip = {
        ...TEST_CLIP,
        metadata: { ...TEST_CLIP.metadata, type: undefined },
      };
      expect(clipEditsDisableVolumeNormalization(clip)).toBe(false);
    });
  });

  describe('getClipDisplayTags', () => {
    it('should return display_tags when available', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        display_tags: 'rock, pop',
      };
      expect(getClipDisplayTags(clip)).toBe('rock, pop');
    });

    it('should return metadata tags as fallback', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        display_tags: null,
        metadata: { ...TEST_CLIP.metadata, tags: 'jazz, blues' },
      };
      expect(getClipDisplayTags(clip)).toBe('jazz, blues');
    });

    it('should prefer display_tags over metadata tags', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        display_tags: 'rock, pop',
        metadata: { ...TEST_CLIP.metadata, tags: 'jazz, blues' },
      };
      expect(getClipDisplayTags(clip)).toBe('rock, pop');
    });

    it('should return empty string when no tags', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        display_tags: null,
        metadata: {},
      };
      expect(getClipDisplayTags(clip)).toBe('');
    });

    it('should return empty string for null clip', () => {
      expect(getClipDisplayTags(null)).toBe('');
    });

    it('should return empty string for undefined clip', () => {
      expect(getClipDisplayTags(undefined)).toBe('');
    });
  });

  describe('getClipFullTags', () => {
    it('should return array of positive tags', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        metadata: { ...TEST_CLIP.metadata, tags: 'rock, pop, jazz' },
      };
      expect(getClipFullTags(clip)).toEqual(['rock', 'pop', 'jazz']);
    });

    it('should include negative tags with prefix', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        metadata: {
          ...TEST_CLIP.metadata,
          tags: 'rock, pop',
          negative_tags: 'metal, punk',
        },
      };
      expect(getClipFullTags(clip)).toEqual(['rock', 'pop', '‑metal', '‑punk']);
    });

    it('should use display_tags when metadata tags not available', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        display_tags: 'blues, soul',
        metadata: {},
      };
      expect(getClipFullTags(clip)).toEqual(['blues', 'soul']);
    });

    it('should return empty array when no tags', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        metadata: {},
      };
      expect(getClipFullTags(clip)).toEqual([]);
    });

    it('should return empty array for null clip', () => {
      expect(getClipFullTags(null)).toEqual([]);
    });

    it('should return empty array for undefined clip', () => {
      expect(getClipFullTags(undefined)).toEqual([]);
    });
  });

  describe('getClipFullTagsString', () => {
    it('should return comma-separated tags', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        metadata: { ...TEST_CLIP.metadata, tags: 'rock, pop, jazz' },
      };
      expect(getClipFullTagsString(clip)).toBe('rock, pop, jazz');
    });

    it('should include negative tags', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        metadata: {
          ...TEST_CLIP.metadata,
          tags: 'rock, pop',
          negative_tags: 'metal',
        },
      };
      expect(getClipFullTagsString(clip)).toBe('rock, pop, ‑metal');
    });

    it('should return empty string when no tags', () => {
      const clip: PartialClip = {
        ...TEST_CLIP,
        metadata: {},
      };
      expect(getClipFullTagsString(clip)).toBe('');
    });

    it('should return empty string for null clip', () => {
      expect(getClipFullTagsString(null)).toBe('');
    });
  });
});
