// src/lib/machines/walletMachine.ts
import { createMachine, assign } from 'xstate';
import { signInWithGoogle } from '../services/signInWithGoogle';
import { createSession } from '../services/createSession';

const walletMachine = createMachine({
    id: 'wallet',
    initial: 'signIn',
    context: {
        provider: null,
        providerName: null,
        authMethod: null,
        pkps: [],
        sessionSigs: null,
        redirect: false
    },
    states: {
        signIn: {
            on: {
                RELOAD: {
                    target: 'sessionAvailable',
                    actions: assign({
                        pkps: (_, event) => event.pkps,
                        sessionSigs: (_, event) => event.sessionSigs,
                    }),
                },
            },
            invoke: {
                src: 'signInWithGoogle',
                onDone: {
                    target: 'authenticated',
                    actions: assign({
                        providerName: (_, event) => event.data.providerName,
                        provider: (_, event) => event.data.provider,
                        authMethod: (_, event) => event.data.authMethod,
                    }),
                },
            },
        },
        authenticated: {
            invoke: {
                src: async (context) => {
                    const pkps = await context.provider.fetchPKPsThroughRelayer(context.authMethod);
                    if (pkps.length === 0) {
                        const newPKP = await context.provider.mintPKP(context.authMethod);
                        pkps.push(newPKP);
                    }
                    return pkps;
                },
                onDone: {
                    target: 'creatingSession',
                    actions: [
                        assign({
                            pkps: (_, event) => event.data,
                        }),
                    ],
                },
                onError: 'authenticated',
            },
        },
        creatingSession: {
            invoke: {
                src: async (context) => {
                    const { pkps, sessionSigs } = await createSession(context.provider, context.authMethod, context.pkps);
                    return { pkps, sessionSigs };
                },
                onDone: {
                    target: 'sessionAvailable',
                    actions: [
                        assign({
                            pkps: (_, event) => event.data.pkps,
                            sessionSigs: (_, event) => event.data.sessionSigs,
                        }),
                    ],
                },
                onError: {
                    target: 'sessionExpired',
                    actions: assign({
                        error: (_, event) => event.data,
                    }),
                },
            },
        },
        sessionAvailable: {
            on: {
                EXPIRED: {
                    target: 'sessionExpired',
                    cond: (context) => context.sessionSigs && Object.values(context.sessionSigs).every(sig => sig.expired)
                },
                LOGOUT: 'sessionExpired'
            }
        },
        sessionExpired: {
            entry: assign({
                sessionSigs: null,
                redirect: true
            }),
            after: {
                0: {
                    target: 'signIn',
                    actions: () => {
                        localStorage.removeItem('me');
                        window.location.href = '/';
                    }
                }
            }
        },
    },
}, {
    services: {
        signInWithGoogle,
        createSession
    },
});

export default walletMachine;
