import { describe, it, expect } from 'vitest';
import type {
  ChallengeFile,
  SavedChallengeFile
} from '../../../redux/prop-types';
import { mergeChallengeFiles } from './saved-challenges';

const jsChallenge = {
  contents: 'js contents',
  fileKey: 'jsFileKey',
  name: 'name',
  ext: 'js' as const,
  history: [],
  seed: 'original js contents',
  path: 'index.js'
};

const cssChallenge = {
  contents: 'css contents',
  fileKey: 'cssFileKey',
  name: 'name',
  ext: 'css' as const,
  history: [],
  seed: 'original css contents',
  path: 'styles.css'
};

const htmlChallenge = {
  contents: 'html contents',
  fileKey: 'htmlFileKey',
  name: 'name',
  ext: 'html' as const,
  history: [],
  seed: 'original html contents',
  path: 'index.html'
};

const savedJsChallenge: SavedChallengeFile = {
  contents: 'saved js contents',
  fileKey: 'jsFileKey',
  name: 'name',
  ext: 'js' as const
};

const savedCssChallenge: SavedChallengeFile = {
  contents: 'saved css contents',
  fileKey: 'cssFileKey',
  name: 'name',
  ext: 'css' as const
};

const savedHtmlChallenge: SavedChallengeFile = {
  contents: 'saved html contents',
  fileKey: 'htmlFileKey',
  name: 'name',
  ext: 'html' as const
};

describe('mergeChallengeFiles', () => {
  it('should return files if savedChallengeFiles is undefined', () => {
    const files: ChallengeFile[] = [htmlChallenge];
    const savedChallengeFiles = undefined;

    const result = mergeChallengeFiles(files, savedChallengeFiles);

    expect(result).toEqual(files);
  });

  it('should return an empty array if files is undefined', () => {
    const files = undefined;
    const savedChallengeFiles = [savedJsChallenge];

    const result = mergeChallengeFiles(files, savedChallengeFiles);

    expect(result).toEqual([]);
  });

  it('should return files if savedChallengeFiles has a different length', () => {
    const files: ChallengeFile[] = [cssChallenge];
    const savedChallengeFiles: SavedChallengeFile[] = [
      savedCssChallenge,
      savedJsChallenge
    ];

    const result = mergeChallengeFiles(files, savedChallengeFiles);

    expect(result).toEqual(files);
  });

  it('should return files if the fileKey properties do not match', () => {
    const files: ChallengeFile[] = [jsChallenge, cssChallenge];
    const savedChallengeFiles: SavedChallengeFile[] = [
      savedHtmlChallenge,
      savedCssChallenge
    ];

    const result = mergeChallengeFiles(files, savedChallengeFiles);

    expect(result).toEqual(files);
  });

  it('should use the contents from the saved file', () => {
    const files: ChallengeFile[] = [cssChallenge, htmlChallenge, jsChallenge];
    const savedChallengeFiles = [
      savedJsChallenge,
      savedCssChallenge,
      savedHtmlChallenge
    ];

    const result = mergeChallengeFiles(files, savedChallengeFiles);

    expect(result).toEqual([
      {
        ...cssChallenge,
        contents: savedCssChallenge.contents
      },
      {
        ...htmlChallenge,
        contents: savedHtmlChallenge.contents
      },
      {
        ...jsChallenge,
        contents: savedJsChallenge.contents
      }
    ]);
  });

  it('should not mutate the original files and savedChallengeFiles arrays', () => {
    const files: ChallengeFile[] = [jsChallenge, cssChallenge];
    const savedChallengeFiles: SavedChallengeFile[] = [
      savedJsChallenge,
      savedCssChallenge
    ];

    const filesCopy = JSON.parse(JSON.stringify(files));
    const savedFilesCopy = JSON.parse(JSON.stringify(savedChallengeFiles));

    mergeChallengeFiles(files, savedChallengeFiles);

    expect(files).toEqual(filesCopy);
    expect(savedChallengeFiles).toEqual(savedFilesCopy);
  });
});
