import { create } from 'zustand' import type { StatementProblem, StatementResult } from '../types' import { judgeStatement } from '../lib/judge' import { fetchStatementProblems } from '../lib/supabase' import { useAuth } from './authStore' export type StatementPhase = 'select' | 'loading' | 'playing' | 'result' // ゲストモード用サンプル問題(貸借対照表の作成) const SAMPLE_STATEMENT: StatementProblem = { id: 'sample-statement-1', section: 'statement', topic: 'fixed_asset', event_text: '下記の決算整理前残高試算表にもとづき、決算整理を行って貸借対照表を完成させなさい。①貸倒引当金:売掛金の2%設定(差額補充法)。②減価償却:建物30年・備品8年(定額法・残存価額¥0)。③未払利息:借入金¥1,000,000の2か月分(年利3.6%・月割)。④消費税精算:仮受消費税-仮払消費税=未払消費税。⑤法人税等:¥100,000。', documents: [ { type: 'table', title: '決算整理前残高試算表(関連部分)', headers: ['勘定科目(借方)', '金額', '勘定科目(貸方)', '金額'], rows: [ ['売掛金', '450,000', '貸倒引当金', '4,000'], ['建物', '2,400,000', '建物減価償却累計額', '1,040,000'], ['備品', '700,000', '備品減価償却累計額', '262,500'], ['仮払消費税', '88,000', '借入金(年利3.6%・残2か月)', '1,000,000'], ['', '', '買掛金', '330,000'], ['', '', '仮受消費税', '160,000'], ], }, ], bs_rows: [ { left: { label: { type: 'given_label', value: '売掛金' }, amount: { type: 'blank_amount', answer: 450000 } }, right: { label: { type: 'given_label', value: '買掛金' }, amount: { type: 'given_amount', value: 330000 } }, }, { left: { label: { type: 'given_label', value: '貸倒引当金' }, amount: { type: 'blank_contra', answer: 9000, answer2: 441000 } }, right: { label: { type: 'given_label', value: '未払費用' }, amount: { type: 'blank_amount', answer: 6000 } }, }, { left: { label: { type: 'given_label', value: '建物' }, amount: { type: 'blank_amount', answer: 2400000 } }, right: { label: { type: 'blank_account', answer: '未払', suffix: '消費税' }, amount: { type: 'blank_amount', answer: 72000 } }, }, { left: { label: { type: 'given_label', value: '建物減価償却累計額' }, amount: { type: 'blank_contra', answer: 1120000, answer2: 1280000 } }, right: { label: { type: 'given_label', value: '未払法人税等' }, amount: { type: 'blank_amount', answer: 100000 } }, }, { left: { label: { type: 'given_label', value: '備品' }, amount: { type: 'blank_amount', answer: 700000 } }, right: { label: { type: 'given_label', value: null }, amount: { type: 'given_amount', value: null } }, }, { left: { label: { type: 'given_label', value: '備品減価償却累計額' }, amount: { type: 'blank_contra', answer: 350000, answer2: 350000 } }, right: { label: { type: 'given_label', value: null }, amount: { type: 'given_amount', value: null } }, }, ], hint: '①9,000(450,000×2%)②建物80,000(÷30)・備品87,500(÷8)③6,000(×3.6%×2/12)④72,000(160,000-88,000)', explanation: '貸倒引当金9,000(追加5,000)。建物累計1,120,000(+80,000)、備品累計350,000(+87,500)。未払費用6,000。未払消費税72,000。未払法人税等100,000。', } interface StatementState { phase: StatementPhase problem: StatementProblem | null inputs: Record result: StatementResult | null error: string | null start: () => Promise setInput: (key: string, value: string | number) => void submit: () => void retry: () => void backToSelect: () => void } export const useStatement = create((set, get) => ({ phase: 'select', problem: null, inputs: {}, result: null, error: null, start: async () => { set({ phase: 'loading', error: null }) const isGuest = useAuth.getState().authStatus === 'guest' if (isGuest) { set({ phase: 'playing', problem: SAMPLE_STATEMENT, inputs: {}, result: null }) return } try { const problems = await fetchStatementProblems() if (problems.length === 0) { set({ phase: 'select', error: '財務諸表問題がまだありません。管理者に問い合わせください。' }) return } set({ phase: 'playing', problem: problems[0], inputs: {}, result: null }) } catch (e) { set({ phase: 'select', error: e instanceof Error ? e.message : '問題の取得に失敗しました。', }) } }, setInput: (key, value) => { set((s) => ({ inputs: { ...s.inputs, [key]: value } })) }, submit: () => { const { problem, inputs } = get() if (!problem) return const result = judgeStatement(problem, inputs) set({ phase: 'result', result }) }, retry: () => { set({ inputs: {}, result: null, phase: 'playing' }) }, backToSelect: () => { set({ phase: 'select', problem: null, inputs: {}, result: null, error: null }) }, }))