import { jest } from '@jest/globals';
import { MeetingRecorder } from '../../public/call/media/meeting-recorder.js';

class MediaStreamMock {
    constructor(tracks = []) {
        this.tracks = tracks;
    }

    getTracks() {
        return this.tracks;
    }

    getAudioTracks() {
        return this.tracks.filter(track => track.kind === 'audio');
    }

    getVideoTracks() {
        return this.tracks.filter(track => track.kind === 'video');
    }
}

class MediaRecorderMock {
    static isTypeSupported() {
        return true;
    }

    constructor(stream, options) {
        this.stream = stream;
        this.mimeType = options.mimeType;
        this.state = 'inactive';
    }

    start() {
        this.state = 'recording';
    }

    stop() {
        this.state = 'inactive';
        this.ondataavailable({ data: new Blob(['recording'], { type: this.mimeType }) });
        this.onstop();
    }
}

function createTrack(kind) {
    return {
        kind,
        readyState: 'live',
        stop: jest.fn(),
        clone: jest.fn(() => createTrack(kind))
    };
}

function createWindowMock({ mediaRecorder = MediaRecorderMock } = {}) {
    return {
        MediaRecorder: mediaRecorder,
        MediaStream: MediaStreamMock,
        URL: {
            createObjectURL: jest.fn(() => 'blob:recording'),
            revokeObjectURL: jest.fn()
        },
        requestAnimationFrame: jest.fn(() => 1),
        cancelAnimationFrame: jest.fn(),
        setTimeout: jest.fn((callback) => {
            callback();
            return 1;
        })
    };
}

describe('MeetingRecorder', () => {
    beforeEach(() => {
        HTMLCanvasElement.prototype.getContext = jest.fn(() => ({
            fillStyle: '',
            font: '',
            textAlign: '',
            textBaseline: '',
            fillRect: jest.fn(),
            fillText: jest.fn(),
            drawImage: jest.fn()
        }));
        HTMLCanvasElement.prototype.captureStream = jest.fn(() => new MediaStreamMock([createTrack('video')]));
    });

    afterEach(() => {
        jest.restoreAllMocks();
        document.body.innerHTML = '';
    });

    test('starts and stops recording a meeting file', async () => {
        const windowRef = createWindowMock();
        const recorder = new MeetingRecorder({ documentRef: document, windowRef });
        const localVideo = document.createElement('video');
        localVideo.id = 'localVideo';
        localVideo.srcObject = new MediaStreamMock([createTrack('video')]);
        Object.defineProperty(localVideo, 'readyState', { value: 2 });
        Object.defineProperty(localVideo, 'videoWidth', { value: 640 });
        Object.defineProperty(localVideo, 'videoHeight', { value: 360 });
        localVideo.getBoundingClientRect = () => ({ width: 320, height: 180 });
        document.body.appendChild(localVideo);

        await recorder.start({
            localStream: new MediaStreamMock([createTrack('audio')]),
            connectionId: '123-456-789'
        });

        expect(recorder.isRecording()).toBe(true);

        const result = await recorder.stop();

        expect(result.filename).toContain('meeting-recording-123-456-789');
        expect(result.mimeType.toLowerCase()).toBe('video/mp4;codecs=avc1.42e01e,mp4a.40.2');
        expect(result.filename).toMatch(/\.mp4$/);
        expect(windowRef.URL.createObjectURL).not.toHaveBeenCalled();
        expect(recorder.isRecording()).toBe(false);
    });

    test('reports unsupported browsers', async () => {
        HTMLCanvasElement.prototype.captureStream = undefined;
        const windowRef = createWindowMock({ mediaRecorder: undefined });
        const recorder = new MeetingRecorder({ documentRef: document, windowRef });

        await expect(recorder.start()).rejects.toThrow('当前浏览器不支持会议录制');
    });
});
