import { describe, it, expect, beforeEach, vi } from 'vitest';
import { useInputBarStore } from '../../src/store/inputBar';

function createMockFile(name: string, type: string): File {
  return new File(['mock'], name, { type });
}

describe('InputBar Store', () => {
  beforeEach(() => {
    useInputBarStore.getState().reset();
  });

  describe('Initial State', () => {
    it('should have correct default values', () => {
      const state = useInputBarStore.getState();
      expect(state.generationType).toBe('video');
      expect(state.mode).toBe('universal');
      expect(state.model).toBe('seedance_2.0');
      expect(state.aspectRatio).toBe('21:9');
      expect(state.duration).toBe(15);
      expect(state.prompt).toBe('');
      expect(state.references).toEqual([]);
      expect(state.firstFrame).toBeNull();
      expect(state.lastFrame).toBeNull();
    });
  });

  describe('Generation Type', () => {
    it('should set generation type', () => {
      useInputBarStore.getState().setGenerationType('image');
      expect(useInputBarStore.getState().generationType).toBe('image');
    });
  });

  describe('Model Selection', () => {
    it('should set model', () => {
      useInputBarStore.getState().setModel('seedance_2.0_fast');
      expect(useInputBarStore.getState().model).toBe('seedance_2.0_fast');
    });
  });

  describe('Aspect Ratio', () => {
    it('should set aspect ratio and save as previous', () => {
      useInputBarStore.getState().setAspectRatio('16:9');
      const state = useInputBarStore.getState();
      expect(state.aspectRatio).toBe('16:9');
      expect(state.prevAspectRatio).toBe('16:9');
    });
  });

  describe('Duration', () => {
    it('should set duration in universal mode and save as previous', () => {
      useInputBarStore.getState().setDuration(10);
      const state = useInputBarStore.getState();
      expect(state.duration).toBe(10);
      expect(state.prevDuration).toBe(10);
    });

    it('should set duration in keyframe mode without saving as previous', () => {
      useInputBarStore.getState().switchMode('keyframe');
      useInputBarStore.getState().setDuration(10);
      const state = useInputBarStore.getState();
      expect(state.duration).toBe(10);
      expect(state.prevDuration).toBe(15); // original default
    });
  });

  describe('Prompt', () => {
    it('should set prompt text', () => {
      useInputBarStore.getState().setPrompt('test prompt');
      expect(useInputBarStore.getState().prompt).toBe('test prompt');
    });
  });

  describe('Universal References', () => {
    it('should add references', () => {
      const files = [createMockFile('img1.jpg', 'image/jpeg')];
      useInputBarStore.getState().addReferences(files);
      expect(useInputBarStore.getState().references).toHaveLength(1);
      expect(useInputBarStore.getState().references[0].type).toBe('image');
    });

    it('should limit references to 5', () => {
      const files = Array.from({ length: 6 }, (_, i) =>
        createMockFile(`img${i}.jpg`, 'image/jpeg')
      );
      useInputBarStore.getState().addReferences(files);
      expect(useInputBarStore.getState().references).toHaveLength(5);
    });

    it('should not add more when already at 5', () => {
      const files = Array.from({ length: 5 }, (_, i) =>
        createMockFile(`img${i}.jpg`, 'image/jpeg')
      );
      useInputBarStore.getState().addReferences(files);
      expect(useInputBarStore.getState().references).toHaveLength(5);

      useInputBarStore.getState().addReferences([createMockFile('extra.jpg', 'image/jpeg')]);
      expect(useInputBarStore.getState().references).toHaveLength(5);
    });

    it('should detect video files correctly', () => {
      const files = [createMockFile('vid.mp4', 'video/mp4')];
      useInputBarStore.getState().addReferences(files);
      expect(useInputBarStore.getState().references[0].type).toBe('video');
    });

    it('should remove a reference by id', () => {
      const files = [createMockFile('img1.jpg', 'image/jpeg')];
      useInputBarStore.getState().addReferences(files);
      const id = useInputBarStore.getState().references[0].id;

      useInputBarStore.getState().removeReference(id);
      expect(useInputBarStore.getState().references).toHaveLength(0);
    });

    it('should call revokeObjectURL when removing reference', () => {
      const files = [createMockFile('img1.jpg', 'image/jpeg')];
      useInputBarStore.getState().addReferences(files);
      const id = useInputBarStore.getState().references[0].id;

      useInputBarStore.getState().removeReference(id);
      expect(URL.revokeObjectURL).toHaveBeenCalled();
    });

    it('should clear all references', () => {
      const files = [
        createMockFile('img1.jpg', 'image/jpeg'),
        createMockFile('img2.jpg', 'image/jpeg'),
      ];
      useInputBarStore.getState().addReferences(files);
      useInputBarStore.getState().clearReferences();
      expect(useInputBarStore.getState().references).toHaveLength(0);
    });
  });

  describe('Keyframe Frames', () => {
    it('should set first frame', () => {
      const file = createMockFile('first.jpg', 'image/jpeg');
      useInputBarStore.getState().setFirstFrame(file);
      const state = useInputBarStore.getState();
      expect(state.firstFrame).not.toBeNull();
      expect(state.firstFrame!.label).toBe('首帧');
    });

    it('should set last frame', () => {
      const file = createMockFile('last.jpg', 'image/jpeg');
      useInputBarStore.getState().setLastFrame(file);
      const state = useInputBarStore.getState();
      expect(state.lastFrame).not.toBeNull();
      expect(state.lastFrame!.label).toBe('尾帧');
    });

    it('should clear first frame when setting null', () => {
      useInputBarStore.getState().setFirstFrame(createMockFile('first.jpg', 'image/jpeg'));
      useInputBarStore.getState().setFirstFrame(null);
      expect(useInputBarStore.getState().firstFrame).toBeNull();
    });

    it('should revoke old URL when replacing frame', () => {
      useInputBarStore.getState().setFirstFrame(createMockFile('a.jpg', 'image/jpeg'));
      useInputBarStore.getState().setFirstFrame(createMockFile('b.jpg', 'image/jpeg'));
      expect(URL.revokeObjectURL).toHaveBeenCalled();
    });
  });

  describe('canSubmit', () => {
    it('should return false when no content', () => {
      expect(useInputBarStore.getState().canSubmit()).toBe(false);
    });

    it('should return true when prompt has text', () => {
      useInputBarStore.getState().setPrompt('hello');
      expect(useInputBarStore.getState().canSubmit()).toBe(true);
    });

    it('should return false for whitespace-only prompt', () => {
      useInputBarStore.getState().setPrompt('   ');
      expect(useInputBarStore.getState().canSubmit()).toBe(false);
    });

    it('should return true when universal references exist', () => {
      useInputBarStore.getState().addReferences([createMockFile('img.jpg', 'image/jpeg')]);
      expect(useInputBarStore.getState().canSubmit()).toBe(true);
    });

    it('should return true when first frame exists in keyframe mode', () => {
      useInputBarStore.getState().switchMode('keyframe');
      useInputBarStore.getState().setFirstFrame(createMockFile('first.jpg', 'image/jpeg'));
      expect(useInputBarStore.getState().canSubmit()).toBe(true);
    });

    it('should return true when last frame exists in keyframe mode', () => {
      useInputBarStore.getState().switchMode('keyframe');
      useInputBarStore.getState().setLastFrame(createMockFile('last.jpg', 'image/jpeg'));
      expect(useInputBarStore.getState().canSubmit()).toBe(true);
    });
  });

  describe('Mode Switching', () => {
    it('should switch to keyframe mode with correct defaults', () => {
      useInputBarStore.getState().switchMode('keyframe');
      const state = useInputBarStore.getState();
      expect(state.mode).toBe('keyframe');
      expect(state.duration).toBe(5);
      expect(state.references).toEqual([]);
    });

    it('should clear universal references when switching to keyframe', () => {
      useInputBarStore.getState().addReferences([createMockFile('img.jpg', 'image/jpeg')]);
      useInputBarStore.getState().switchMode('keyframe');
      expect(useInputBarStore.getState().references).toEqual([]);
    });

    it('should restore aspect ratio and duration when switching back to universal', () => {
      useInputBarStore.getState().setAspectRatio('16:9');
      useInputBarStore.getState().setDuration(10);
      useInputBarStore.getState().switchMode('keyframe');
      useInputBarStore.getState().switchMode('universal');

      const state = useInputBarStore.getState();
      expect(state.aspectRatio).toBe('16:9');
      expect(state.duration).toBe(10);
    });

    it('should clear keyframe data when switching back to universal', () => {
      useInputBarStore.getState().switchMode('keyframe');
      useInputBarStore.getState().setFirstFrame(createMockFile('first.jpg', 'image/jpeg'));
      useInputBarStore.getState().setLastFrame(createMockFile('last.jpg', 'image/jpeg'));
      useInputBarStore.getState().switchMode('universal');

      const state = useInputBarStore.getState();
      expect(state.firstFrame).toBeNull();
      expect(state.lastFrame).toBeNull();
    });

    it('should not do anything when switching to same mode', () => {
      useInputBarStore.getState().setPrompt('test');
      useInputBarStore.getState().switchMode('universal');
      expect(useInputBarStore.getState().prompt).toBe('test');
    });

    it('should preserve prompt text across mode switches', () => {
      useInputBarStore.getState().setPrompt('my prompt');
      useInputBarStore.getState().switchMode('keyframe');
      expect(useInputBarStore.getState().prompt).toBe('my prompt');
      useInputBarStore.getState().switchMode('universal');
      expect(useInputBarStore.getState().prompt).toBe('my prompt');
    });
  });

  describe('Reset', () => {
    it('should reset all state to defaults', () => {
      useInputBarStore.getState().setPrompt('hello');
      useInputBarStore.getState().setModel('seedance_2.0_fast');
      useInputBarStore.getState().setAspectRatio('16:9');
      useInputBarStore.getState().setDuration(5);
      useInputBarStore.getState().addReferences([createMockFile('img.jpg', 'image/jpeg')]);

      useInputBarStore.getState().reset();
      const state = useInputBarStore.getState();
      expect(state.prompt).toBe('');
      expect(state.model).toBe('seedance_2.0');
      expect(state.aspectRatio).toBe('21:9');
      expect(state.duration).toBe(15);
      expect(state.references).toEqual([]);
      expect(state.mode).toBe('universal');
      expect(state.generationType).toBe('video');
    });
  });
});
