import { useState, useEffect, useCallback, Dispatch, SetStateAction } from 'react';
import { v4 as uuidv4 } from 'uuid';
import { webSocketService } from '../services/websocket'; // Import the websocket service

// Define the types for the session state based on data-model.md
// In a real app, these would be in a separate types file.
export interface Participant {
    participantId: string; // This will now be the clientId
    isCreator: boolean;
    hasSubmitted: boolean;
}

export interface DesireSet {
    participantId: string;
    wants: string[];
    accepts: string[];
    noGoes: string[];
    afraidToAsk: string; // Add afraidToAsk to DesireSet
}

export interface Decision {
    goTo: string;
    alsoGood: string;
    considerable: string;
    noGoes: string;
    needsDiscussion: string;
}

// Define the SessionState enum (mirroring backend)
export enum SessionState {
    SETUP = 'SETUP',
    GATHERING = 'GATHERING',
    HARMONIZING = 'HARMONIZING',
    FINAL = 'FINAL',
    ERROR = 'ERROR',
}

export interface Session {
    sessionId: string;
    state: SessionState;
    expectedResponses: number;
    submittedCount: number;
    responses: { [clientId: string]: DesireSet }; // Map of clientId to their submitted DesireSet
    finalResult: Decision | null;
    topic?: string; // This might be part of the initial setup payload
    description?: string; // Add description field
}

// Utility to generate a persistent client ID
const getOrCreateClientId = (): string => {
    let clientId = localStorage.getItem('clientId');
    if (!clientId) {
        clientId = uuidv4();
        localStorage.setItem('clientId', clientId);
    }
    return clientId;
};

export const useSession = (sessionId: string): [Session | null, Dispatch<SetStateAction<Session | null>>, (message: any) => void, string, string | null] => {
    const clientId = getOrCreateClientId(); // Get or create clientId
    const [error, setError] = useState<string | null>(null);

    const getInitialState = useCallback((): Session | null => {
        try {
            const item = window.localStorage.getItem(`session-${sessionId}`);
            return item ? JSON.parse(item) : null;
        } catch (error) {
            console.error('Error reading from localStorage', error);
            return null;
        }
    }, [sessionId]);

    const [session, setSession] = useState<Session | null>(getInitialState);

    useEffect(() => {
        // Connect to WebSocket
        webSocketService.connect(sessionId, clientId);

        // Handle incoming messages
        const handleMessage = (message: any) => {
            console.log('useSession: Processing incoming message:', message);
            if (message.type === 'STATE_UPDATE') {
                console.log('useSession: Received STATE_UPDATE, session payload:', message.payload.session);
                setSession(message.payload.session);
                setError(null); // Clear error on successful state update
            } else if (message.type === 'ERROR') {
                console.error('WebSocket Error:', message.payload.message);
                setError(message.payload.message);
            }
            // Add other message types as needed
        };

        webSocketService.onMessage(handleMessage);

        const handleError = () => {
            setError('Connection to the session server failed. Please check your connection and try again.');
        };
        webSocketService.onError(handleError);

        const handleSessionTerminated = () => {
            setSession(prevSession => {
                if (prevSession) {
                    return { ...prevSession, state: SessionState.FINAL, finalResult: null }; // Or a specific TERMINATED state
                }
                return null;
            });
            setError('Session terminated by server.');
        };
        webSocketService.onSessionTerminated(handleSessionTerminated);

        // Clean up on unmount
        return () => {
            webSocketService.removeMessageHandler(handleMessage);
            webSocketService.removeSessionTerminatedHandler(handleSessionTerminated);
            webSocketService.disconnect();
        };
    }, [sessionId, clientId]); // Re-run effect if sessionId or clientId changes

    useEffect(() => {
        try {
            if (session) {
                window.localStorage.setItem(`session-${sessionId}`, JSON.stringify(session));
            }
        } catch (error) {
            console.error('Error writing to localStorage', error);
        }
    }, [session, sessionId]);

    const sendMessage = useCallback((message: any) => {
        webSocketService.sendMessage(message);
    }, []);

    return [session, setSession, sendMessage, clientId, error];
};

