/**
 * Store para gerenciar estado das chamadas de áudio/vídeo
 */

import { writable, derived, get } from 'svelte/store';
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
import type { JitsiApi } from '$lib/types/jitsi';

export interface ParticipanteChamada {
	usuarioId: Id<'usuarios'>;
	nome: string;
	avatar?: string;
	audioHabilitado: boolean;
	videoHabilitado: boolean;
	forcadoPeloAnfitriao?: boolean;
	participantId?: string; // ID do participante no Jitsi
}

export interface EstadoChamada {
	chamadaId: Id<'chamadas'> | null;
	conversaId: Id<'conversas'> | null;
	tipo: 'audio' | 'video' | null;
	roomName: string | null;
	estaConectado: boolean;
	audioHabilitado: boolean;
	videoHabilitado: boolean;
	gravando: boolean;
	ehAnfitriao: boolean;
	participantes: ParticipanteChamada[];
	duracaoSegundos: number;
	dispositivos: {
		microphoneId: string | null;
		cameraId: string | null;
		speakerId: string | null;
	};
	jitsiApi: JitsiApi;
	streamLocal: MediaStream | null;
}

const estadoInicial: EstadoChamada = {
	chamadaId: null,
	conversaId: null,
	tipo: null,
	roomName: null,
	estaConectado: false,
	audioHabilitado: true,
	videoHabilitado: false,
	gravando: false,
	ehAnfitriao: false,
	participantes: [],
	duracaoSegundos: 0,
	dispositivos: {
		microphoneId: null,
		cameraId: null,
		speakerId: null
	},
	jitsiApi: null,
	streamLocal: null
};

// Store principal do estado da chamada
export const callState = writable<EstadoChamada>(estadoInicial);

// Store para indicar se há chamada ativa
export const chamadaAtiva = derived(callState, ($state) => $state.chamadaId !== null);

// Store para indicar se está conectado
export const estaConectado = derived(callState, ($state) => $state.estaConectado);

// Store para indicar se está gravando
export const gravando = derived(callState, ($state) => $state.gravando);

// Funções para atualizar o estado

/**
 * Inicializar chamada
 */
export function inicializarChamada(
	chamadaId: Id<'chamadas'>,
	conversaId: Id<'conversas'>,
	tipo: 'audio' | 'video',
	roomName: string,
	ehAnfitriao: boolean,
	participantes: ParticipanteChamada[]
): void {
	callState.set({
		...estadoInicial,
		chamadaId,
		conversaId,
		tipo,
		roomName,
		ehAnfitriao,
		participantes,
		videoHabilitado: tipo === 'video'
	});
}

/**
 * Finalizar chamada e limpar estado
 */
export function finalizarChamada(): void {
	const estadoAtual = get(callState);

	// Liberar recursos
	if (estadoAtual.streamLocal) {
		estadoAtual.streamLocal.getTracks().forEach((track) => track.stop());
	}

	callState.set(estadoInicial);
}

/**
 * Atualizar status de conexão
 */
export function atualizarStatusConexao(estaConectado: boolean): void {
	callState.update((state) => ({
		...state,
		estaConectado
	}));
}

/**
 * Toggle áudio
 */
export function toggleAudio(): void {
	callState.update((state) => ({
		...state,
		audioHabilitado: !state.audioHabilitado
	}));
}

/**
 * Toggle vídeo
 */
export function toggleVideo(): void {
	callState.update((state) => ({
		...state,
		videoHabilitado: !state.videoHabilitado
	}));
}

/**
 * Definir áudio habilitado/desabilitado
 */
export function setAudioHabilitado(habilitado: boolean): void {
	callState.update((state) => ({
		...state,
		audioHabilitado: habilitado
	}));
}

/**
 * Definir vídeo habilitado/desabilitado
 */
export function setVideoHabilitado(habilitado: boolean): void {
	callState.update((state) => ({
		...state,
		videoHabilitado: habilitado
	}));
}

/**
 * Atualizar lista de participantes
 */
export function atualizarParticipantes(participantes: ParticipanteChamada[]): void {
	callState.update((state) => ({
		...state,
		participantes
	}));
}

/**
 * Adicionar participante
 */
export function adicionarParticipante(participante: ParticipanteChamada): void {
	callState.update((state) => {
		// Verificar se já existe
		const existe = state.participantes.some((p) => p.usuarioId === participante.usuarioId);

		if (existe) {
			return state;
		}

		return {
			...state,
			participantes: [...state.participantes, participante]
		};
	});
}

/**
 * Remover participante
 */
export function removerParticipante(usuarioId: Id<'usuarios'>): void {
	callState.update((state) => ({
		...state,
		participantes: state.participantes.filter((p) => p.usuarioId !== usuarioId)
	}));
}

/**
 * Atualizar status de áudio/vídeo de participante
 */
export function atualizarParticipanteMidia(
	usuarioId: Id<'usuarios'>,
	audioHabilitado?: boolean,
	videoHabilitado?: boolean
): void {
	callState.update((state) => ({
		...state,
		participantes: state.participantes.map((p) =>
			p.usuarioId === usuarioId
				? {
						...p,
						audioHabilitado: audioHabilitado ?? p.audioHabilitado,
						videoHabilitado: videoHabilitado ?? p.videoHabilitado
					}
				: p
		)
	}));
}

/**
 * Iniciar gravação
 */
export function iniciarGravacao(): void {
	callState.update((state) => ({
		...state,
		gravando: true
	}));
}

/**
 * Parar gravação
 */
export function pararGravacao(): void {
	callState.update((state) => ({
		...state,
		gravando: false
	}));
}

/**
 * Atualizar duração da chamada
 */
export function atualizarDuracao(segundos: number): void {
	callState.update((state) => ({
		...state,
		duracaoSegundos: segundos
	}));
}

/**
 * Atualizar dispositivos selecionados
 */
export function atualizarDispositivos(dispositivos: {
	microphoneId?: string | null;
	cameraId?: string | null;
	speakerId?: string | null;
}): void {
	callState.update((state) => ({
		...state,
		dispositivos: {
			...state.dispositivos,
			...dispositivos
		}
	}));
}

/**
 * Definir API Jitsi
 */
export function setJitsiApi(api: JitsiApi): void {
	callState.update((state) => ({
		...state,
		jitsiApi: api
	}));
}

/**
 * Definir stream local
 */
export function setStreamLocal(stream: MediaStream | null): void {
	callState.update((state) => {
		// Parar stream anterior se existir
		if (state.streamLocal) {
			state.streamLocal.getTracks().forEach((track) => track.stop());
		}

		return {
			...state,
			streamLocal: stream
		};
	});
}

/**
 * Obter estado atual (helper)
 */
export function obterEstadoAtual(): EstadoChamada {
	return get(callState);
}

/**
 * Resetar estado (para cleanup)
 */
export function resetarEstado(): void {
	finalizarChamada();
}
