/**
 * Utilitários para gravação de mídia usando MediaRecorder API
 */

export interface OpcoesGravacao {
	audioBitsPerSecond?: number;
	videoBitsPerSecond?: number;
	mimeType?: string;
}

export interface ResultadoGravacao {
	blob: Blob;
	duracaoSegundos: number;
	nomeArquivo: string;
}

/**
 * Verificar se MediaRecorder está disponível no navegador
 */
export function verificarSuporteMediaRecorder(): boolean {
	return typeof MediaRecorder !== 'undefined' && MediaRecorder.isTypeSupported !== undefined;
}

/**
 * Obter tipos MIME suportados para gravação
 */
export function obterTiposMimeSuportados(): {
	video: string[];
	audio: string[];
} {
	if (!verificarSuporteMediaRecorder()) {
		return { video: [], audio: [] };
	}

	const tiposVideo: string[] = [];
	const tiposAudio: string[] = [];

	// Tipos comuns de vídeo
	const tiposVideoComuns = [
		'video/webm',
		'video/webm;codecs=vp9',
		'video/webm;codecs=vp8',
		'video/webm;codecs=h264',
		'video/mp4',
		'video/ogg',
		'video/x-matroska'
	];

	// Tipos comuns de áudio
	const tiposAudioComuns = [
		'audio/webm',
		'audio/webm;codecs=opus',
		'audio/ogg',
		'audio/mp4',
		'audio/mpeg'
	];

	for (const tipo of tiposVideoComuns) {
		if (MediaRecorder.isTypeSupported(tipo)) {
			tiposVideo.push(tipo);
		}
	}

	for (const tipo of tiposAudioComuns) {
		if (MediaRecorder.isTypeSupported(tipo)) {
			tiposAudio.push(tipo);
		}
	}

	return { video: tiposVideo, audio: tiposAudio };
}

/**
 * Iniciar gravação de áudio apenas
 */
export function iniciarGravacaoAudio(
	stream: MediaStream,
	opcoes?: OpcoesGravacao
): MediaRecorder | null {
	if (!verificarSuporteMediaRecorder()) {
		console.error('MediaRecorder não está disponível neste navegador');
		return null;
	}

	try {
		const tiposAudio = obterTiposMimeSuportados().audio;
		const mimeType = opcoes?.mimeType || tiposAudio[0] || 'audio/webm';

		const recorder = new MediaRecorder(stream, {
			mimeType,
			audioBitsPerSecond: opcoes?.audioBitsPerSecond || 128000
		});

		return recorder;
	} catch (error) {
		console.error('Erro ao iniciar gravação de áudio:', error);
		return null;
	}
}

/**
 * Iniciar gravação de vídeo (áudio + vídeo)
 */
export function iniciarGravacaoVideo(
	stream: MediaStream,
	opcoes?: OpcoesGravacao
): MediaRecorder | null {
	if (!verificarSuporteMediaRecorder()) {
		console.error('MediaRecorder não está disponível neste navegador');
		return null;
	}

	try {
		const tiposVideo = obterTiposMimeSuportados().video;
		const mimeType = opcoes?.mimeType || tiposVideo[0] || 'video/webm';

		const recorder = new MediaRecorder(stream, {
			mimeType,
			audioBitsPerSecond: opcoes?.audioBitsPerSecond || 128000,
			videoBitsPerSecond: opcoes?.videoBitsPerSecond || 2500000
		});

		return recorder;
	} catch (error) {
		console.error('Erro ao iniciar gravação de vídeo:', error);
		return null;
	}
}

/**
 * Parar gravação e retornar blob
 */
export function pararGravacao(recorder: MediaRecorder): Promise<Blob> {
	return new Promise((resolve, reject) => {
		const chunks: BlobPart[] = [];

		recorder.ondataavailable = (event) => {
			if (event.data && event.data.size > 0) {
				chunks.push(event.data);
			}
		};

		recorder.onstop = () => {
			const blob = new Blob(chunks, { type: recorder.mimeType });
			resolve(blob);
		};

		recorder.onerror = (event) => {
			console.error('Erro na gravação:', event);
			reject(new Error('Erro ao parar gravação'));
		};

		if (recorder.state === 'recording') {
			recorder.stop();
		} else {
			reject(new Error('Recorder não está gravando'));
		}
	});
}

/**
 * Salvar gravação localmente
 */
export function salvarGravacao(blob: Blob, nomeArquivo: string): void {
	try {
		const url = URL.createObjectURL(blob);
		const link = document.createElement('a');
		link.href = url;
		link.download = nomeArquivo;
		document.body.appendChild(link);
		link.click();
		document.body.removeChild(link);
		URL.revokeObjectURL(url);
	} catch (error) {
		console.error('Erro ao salvar gravação:', error);
		throw error;
	}
}

/**
 * Gerar nome de arquivo para gravação
 */
export function gerarNomeArquivo(
	tipo: 'audio' | 'video',
	roomName: string,
	timestamp?: number
): string {
	const agora = timestamp || Date.now();
	const data = new Date(agora);
	const dataFormatada = data.toISOString().replace(/[:.]/g, '-').split('T')[0];
	const horaFormatada = data.toLocaleTimeString('pt-BR', { hour12: false }).replace(/:/g, '-');
	const extensao = tipo === 'audio' ? 'webm' : 'webm';

	return `gravacao-${tipo}-${roomName}-${dataFormatada}-${horaFormatada}.${extensao}`;
}

/**
 * Obter tamanho do blob em formato legível
 */
export function formatarTamanhoBlob(bytes: number): string {
	if (bytes === 0) return '0 Bytes';

	const k = 1024;
	const sizes = ['Bytes', 'KB', 'MB', 'GB'];
	const i = Math.floor(Math.log(bytes) / Math.log(k));

	return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
}

/**
 * Calcular duração de gravação (em segundos)
 */
export function calcularDuracaoGravacao(inicioTimestamp: number, fimTimestamp?: number): number {
	const fim = fimTimestamp || Date.now();
	return Math.floor((fim - inicioTimestamp) / 1000);
}

/**
 * Gravar com controle completo
 */
export class GravadorMedia {
	private recorder: MediaRecorder | null = null;
	private stream: MediaStream | null = null;
	private inicioTimestamp: number = 0;
	private chunks: BlobPart[] = [];

	constructor(
		private streamOriginal: MediaStream,
		private tipo: 'audio' | 'video',
		private opcoes?: OpcoesGravacao
	) {
		this.stream = streamOriginal;
	}

	iniciar(): boolean {
		if (this.recorder && this.recorder.state === 'recording') {
			console.warn('Gravação já está em andamento');
			return false;
		}

		try {
			this.recorder =
				this.tipo === 'audio'
					? iniciarGravacaoAudio(this.stream!, this.opcoes)
					: iniciarGravacaoVideo(this.stream!, this.opcoes);

			if (!this.recorder) {
				return false;
			}

			this.chunks = [];
			this.inicioTimestamp = Date.now();

			this.recorder.ondataavailable = (event) => {
				if (event.data && event.data.size > 0) {
					this.chunks.push(event.data);
				}
			};

			this.recorder.start(1000); // Coletar dados a cada segundo
			return true;
		} catch (error) {
			console.error('Erro ao iniciar gravação:', error);
			return false;
		}
	}

	parar(): Promise<Blob> {
		return new Promise((resolve, reject) => {
			if (!this.recorder) {
				reject(new Error('Recorder não foi inicializado'));
				return;
			}

			if (this.recorder.state === 'inactive') {
				// Se já parou, retornar blob dos chunks
				if (this.chunks.length > 0) {
					const blob = new Blob(this.chunks, { type: this.recorder.mimeType });
					resolve(blob);
				} else {
					reject(new Error('Nenhum dado gravado'));
				}
				return;
			}

			this.recorder.onstop = () => {
				const blob = new Blob(this.chunks, { type: this.recorder!.mimeType });
				resolve(blob);
			};

			this.recorder.onerror = (event) => {
				console.error('Erro na gravação:', event);
				reject(new Error('Erro ao parar gravação'));
			};

			this.recorder.stop();
		});
	}

	obterDuracaoSegundos(): number {
		if (this.inicioTimestamp === 0) return 0;
		return calcularDuracaoGravacao(this.inicioTimestamp);
	}

	estaGravando(): boolean {
		return this.recorder?.state === 'recording';
	}

	liberar(): void {
		if (this.recorder && this.recorder.state === 'recording') {
			this.recorder.stop();
		}

		// Parar todas as tracks do stream
		if (this.stream) {
			this.stream.getTracks().forEach((track) => track.stop());
		}

		this.recorder = null;
		this.stream = null;
		this.chunks = [];
		this.inicioTimestamp = 0;
	}
}
