'use client' import { useCallback, useEffect, useMemo, useState } from 'react' import { defaultFoundingWizardState, type FoundingWizardState, type Gesellschafter, type GFContract, type GeneratedDocument, } from '@/lib/sdk/founding/types' const STORAGE_KEY = 'breakpilot:founding-wizard:state:v1' export const FOUNDING_WIZARD_STEPS = [ { id: 1, name: 'Stage & Basics', description: 'Unternehmensname, Sitz, Gegenstand' }, { id: 2, name: 'Gesellschafter', description: 'Gründer und ihre Anteile' }, { id: 3, name: 'Geschäftsführer', description: 'GF-Bestellung und Rollen' }, { id: 4, name: 'Kapital', description: 'Stammkapital und Einzahlung' }, { id: 5, name: 'Notar', description: 'Notartermin und Beurkundung' }, { id: 6, name: 'SHA-Optionen', description: 'Vesting, Drag-Along, Reserved Matters' }, { id: 7, name: 'GF-Verträge', description: 'Vergütung, D&O, Kündigungsfristen' }, { id: 8, name: 'Dokumente generieren', description: 'Auswahl und Word-Export' }, ] export function useFoundingWizardForm() { const [state, setState] = useState(defaultFoundingWizardState()) const [hydrated, setHydrated] = useState(false) const [generating, setGenerating] = useState(false) const [error, setError] = useState(null) // Hydrate from localStorage useEffect(() => { try { const raw = localStorage.getItem(STORAGE_KEY) if (raw) { const parsed = JSON.parse(raw) setState({ ...defaultFoundingWizardState(), ...parsed }) } } catch { // ignore corrupted storage } setHydrated(true) }, []) // Persist on every change after hydration useEffect(() => { if (!hydrated) return try { localStorage.setItem(STORAGE_KEY, JSON.stringify(state)) } catch { // quota exceeded - ignore } }, [state, hydrated]) const update = useCallback(( key: K, value: FoundingWizardState[K] | ((prev: FoundingWizardState[K]) => FoundingWizardState[K]) ) => { setState(prev => ({ ...prev, [key]: typeof value === 'function' ? (value as Function)(prev[key]) : value, })) }, []) const setStep = useCallback((step: number) => { setState(prev => ({ ...prev, current_step: step })) }, []) const nextStep = useCallback(() => { setState(prev => ({ ...prev, current_step: Math.min(prev.current_step + 1, FOUNDING_WIZARD_STEPS.length) })) }, []) const prevStep = useCallback(() => { setState(prev => ({ ...prev, current_step: Math.max(prev.current_step - 1, 1) })) }, []) const reset = useCallback(() => { setState(defaultFoundingWizardState()) try { localStorage.removeItem(STORAGE_KEY) } catch {} }, []) // Gesellschafter helpers const addGesellschafter = useCallback((gs: Omit) => { setState(prev => { const nextNr = (prev.gesellschafter.reduce((m, g) => Math.max(m, g.anteil_nr), 0)) + 1 const id = `gs_${Date.now()}_${nextNr}` return { ...prev, gesellschafter: [...prev.gesellschafter, { ...gs, id, anteil_nr: nextNr }] } }) }, []) const updateGesellschafter = useCallback((id: string, patch: Partial) => { setState(prev => ({ ...prev, gesellschafter: prev.gesellschafter.map(g => g.id === id ? { ...g, ...patch } : g), })) }, []) const removeGesellschafter = useCallback((id: string) => { setState(prev => ({ ...prev, gesellschafter: prev.gesellschafter.filter(g => g.id !== id), gf_contracts: prev.gf_contracts.filter(c => c.gesellschafter_id !== id), })) }, []) // GF Contract helpers const upsertGFContract = useCallback((contract: GFContract) => { setState(prev => { const idx = prev.gf_contracts.findIndex(c => c.gesellschafter_id === contract.gesellschafter_id) const next = [...prev.gf_contracts] if (idx >= 0) next[idx] = contract else next.push(contract) return { ...prev, gf_contracts: next } }) }, []) // Validation (canProceed for current step) const canProceed = useMemo(() => { switch (state.current_step) { case 1: return state.basics.company_name.trim().length > 1 && state.basics.company_seat.trim().length > 1 && state.basics.company_purpose_description.trim().length > 10 case 2: { if (state.gesellschafter.length < 1) return false const sum = state.gesellschafter.reduce((s, g) => s + (g.nennbetrag_eur || 0), 0) return sum === state.capital.stammkapital_eur } case 3: return state.gesellschafter.some(g => g.is_geschaeftsfuehrer) case 4: return state.capital.stammkapital_eur >= 25000 case 5: return state.notar.notary_name.trim().length > 1 && state.notar.notary_place.trim().length > 1 case 6: return true case 7: return state.gesellschafter.filter(g => g.is_geschaeftsfuehrer) .every(g => state.gf_contracts.some(c => c.gesellschafter_id === g.id)) case 8: return state.selected_documents.length > 0 default: return false } }, [state]) const generateDocuments = useCallback(async (): Promise => { setGenerating(true) setError(null) try { const response = await fetch('/api/v1/founding-wizard/generate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(state), }) if (!response.ok) { throw new Error(`Generierung fehlgeschlagen: ${response.status}`) } const data = await response.json() const docs: GeneratedDocument[] = data.documents || [] setState(prev => ({ ...prev, generated_documents: docs })) return docs } catch (e: unknown) { const msg = e instanceof Error ? e.message : 'Unbekannter Fehler' setError(msg) throw e } finally { setGenerating(false) } }, [state]) // Derived: hat zugehöriger GF einen Vertrag? const gf_list = useMemo( () => state.gesellschafter.filter(g => g.is_geschaeftsfuehrer), [state.gesellschafter] ) return { state, hydrated, generating, error, update, setStep, nextStep, prevStep, reset, addGesellschafter, updateGesellschafter, removeGesellschafter, upsertGFContract, canProceed, generateDocuments, gf_list, steps: FOUNDING_WIZARD_STEPS, } }