const { useState, useEffect, useRef, useCallback, useMemo } = React;

const API = window.location.origin;

/* ---- View Transition Wrapper ---- */
function ViewTransition({ viewKey, children }) {
    const [visible, setVisible] = useState(true);
    const [rendered, setRendered] = useState({ key: viewKey, content: children });
    const prevKey = useRef(viewKey);

    useEffect(() => {
        if (viewKey !== prevKey.current) {
            setVisible(false);
            const timer = setTimeout(() => {
                setRendered({ key: viewKey, content: children });
                setVisible(true);
                prevKey.current = viewKey;
            }, 180);
            return () => clearTimeout(timer);
        } else {
            setRendered({ key: viewKey, content: children });
        }
    }, [viewKey, children]);

    return (
        <div className={`view-transition ${visible ? 'visible' : 'hidden'}`}>
            {rendered.content}
        </div>
    );
}

/* ---- Skeleton Loader ---- */
function SkeletonLoader() {
    return (
        <div className="skeleton-container">
            <div className="skeleton-row" style={{width: '45%'}}></div>
            <div className="skeleton-row" style={{width: '70%'}}></div>
            <div className="skeleton-row" style={{width: '55%'}}></div>
            <div className="skeleton-row" style={{width: '80%'}}></div>
            <div className="skeleton-row" style={{width: '35%'}}></div>
        </div>
    );
}

const COLORS = {
    red: '#ef4444', orange: '#f59e0b', green: '#22c55e',
    blue: '#3b82f6', purple: '#a855f7', accent: '#6366f1',
    cyan: '#06b6d4', pink: '#ec4899',
};

const PROJECT_COLORS = ['#6366f1', '#ec4899', '#f59e0b', '#22c55e', '#3b82f6', '#a855f7', '#06b6d4', '#ef4444'];

/* ---- Login Screen ---- */
function LoginScreen({ onLogin }) {
    const [user, setUser] = useState('');
    const [pass, setPass] = useState('');
    const [error, setError] = useState('');
    const [loading, setLoading] = useState(false);

    const submit = async (e) => {
        e.preventDefault();
        setLoading(true);
        setError('');
        try {
            const res = await fetch(`${API}/api/login`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ username: user, password: pass }),
            });
            const data = await res.json();
            if (data.ok) {
                localStorage.setItem('dashboard_token', data.token);
                onLogin(data.token);
            } else {
                setError('Falscher Benutzername oder Passwort');
            }
        } catch {
            setError('Verbindungsfehler');
        }
        setLoading(false);
    };

    return (
        <div className="login-screen">
            <form className="login-box" onSubmit={submit}>
                <div className="login-icon">◉</div>
                <h2>Dashboard</h2>
                <input className="login-input" type="text" placeholder="Benutzername" value={user} onChange={e => setUser(e.target.value)} autoComplete="username" autoFocus />
                <input className="login-input" type="password" placeholder="Passwort" value={pass} onChange={e => setPass(e.target.value)} autoComplete="current-password" />
                {error && <div className="login-error">{error}</div>}
                <button className="login-btn" type="submit" disabled={loading}>
                    {loading ? 'Laden...' : 'Anmelden'}
                </button>
            </form>
        </div>
    );
}

/* ---- Root App with Auth ---- */
function Root() {
    const [token, setToken] = useState(localStorage.getItem('dashboard_token'));

    if (!token) return <LoginScreen onLogin={setToken} />;
    return <App token={token} onLogout={() => { localStorage.removeItem('dashboard_token'); setToken(null); }} />;
}

function App({ token, onLogout }) {
    const [data, setData] = useState(null);
    const [view, setView] = useState("overview");
    const [selectedProject, setSelectedProject] = useState(null);
    const [chatMessages, setChatMessages] = useState([
        { role: "bot", text: "Hallo Simon! Ich bin dein Dashboard-Assistent. Frag mich was zu deinen Projekten, z.B. \"Was soll ich heute machen?\" oder \"Wie steht es um MPM?\"" }
    ]);
    const [loading, setLoading] = useState(true);
    const [completedToast, setCompletedToast] = useState(null);

    const reload = useCallback(() => {
        fetch(`${API}/api/dashboard`)
            .then(r => r.json())
            .then(d => { setData(d); setLoading(false); })
            .catch(() => setLoading(false));
    }, []);

    useEffect(() => { reload(); }, [reload]);

    const completeTask = async (taskId, rowEl) => {
        if (!taskId) return;
        // Haptic feedback
        if (navigator.vibrate) navigator.vibrate(10);
        // Animate row out
        if (rowEl) {
            rowEl.closest('.task-row')?.classList.add('completing');
        }
        try {
            await new Promise(r => setTimeout(r, 300)); // wait for animation
            const res = await fetch(`${API}/api/tasks/complete`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ task_id: taskId }),
            });
            const result = await res.json();
            if (result.ok) {
                setCompletedToast(result.task?.substring(0, 40) || 'Task erledigt');
                setTimeout(() => setCompletedToast(null), 2500);
            }
            reload();
        } catch (e) { console.error(e); }
    };

    if (loading) return <div className="layout"><div className="main"><div className="content"><SkeletonLoader /></div></div></div>;
    if (!data) return <div className="layout"><div className="main"><div className="content"><p>Keine Daten.</p></div></div></div>;

    const { summary, projects, project_tree } = data;
    const urgent = projects.filter(p => p.overdue || (p.days_left !== null && p.days_left <= 7)).length;

    const viewTitles = {
        overview: 'Eisenhower Matrix', projects: 'Projekte', tasks: 'Alle Tasks',
        chat: 'Assistent', detail: projects.find(p => p.id === selectedProject)?.name || '',
        activity: 'Aktivitaet',
    };

    return (
        <div className="layout">
            <div className="sidebar">
                <div className="sidebar-header">
                    <h1>Dashboard</h1>
                    <div className="subtitle">Personal Assistant</div>
                </div>
                <nav className="sidebar-nav">
                    <div className="nav-section">
                        <div className="nav-section-label">Views</div>
                        {[
                            ['overview', '◉', 'Eisenhower'],
                            ['projects', '▦', 'Projekte', projects.length],
                            ['tasks', '☐', 'Tasks', summary.total_open_tasks],
                            ['activity', '◷', 'Aktivitaet'],
                            ['chat', '◈', 'Assistent'],
                        ].map(([v, icon, label, count]) => (
                            <button key={v} className={`nav-item ${view === v ? 'active' : ''}`}
                                onClick={() => { setView(v); setSelectedProject(null); }}>
                                <span className="icon">{icon}</span> {label}
                                {count !== undefined && <span className="count">{count}</span>}
                            </button>
                        ))}
                    </div>
                    <div className="nav-section">
                        <div className="nav-section-label">Projekte</div>
                        {(project_tree || projects).map((p, i) => (
                            <React.Fragment key={p.id}>
                                <button className={`nav-item ${selectedProject === p.id ? 'active' : ''}`}
                                    onClick={() => { setSelectedProject(p.id); setView('detail'); }}>
                                    <span className="icon" style={{color: PROJECT_COLORS[i % PROJECT_COLORS.length]}}>●</span>
                                    {p.name.length > 22 ? p.name.slice(0, 20) + '..' : p.name}
                                    <span className="count">{p.total_count || p.open_count}</span>
                                </button>
                                {p.sub_projects && p.sub_projects.map(sp => (
                                    <button key={sp.id} className={`nav-item ${selectedProject === sp.id ? 'active' : ''}`}
                                        onClick={() => { setSelectedProject(sp.id); setView('detail'); }}
                                        style={{paddingLeft: 32}}>
                                        <span className="icon" style={{color: PROJECT_COLORS[i % PROJECT_COLORS.length], opacity: 0.6, fontSize: 12}}>└</span>
                                        {sp.name.length > 18 ? sp.name.slice(0, 16) + '..' : sp.name}
                                        <span className="count">{sp.open_count}</span>
                                    </button>
                                ))}
                            </React.Fragment>
                        ))}
                    </div>
                </nav>
                <div className="sidebar-footer">
                    <div>Sync: {summary.synced_at ? new Date(summary.synced_at).toLocaleString('de-CH') : 'nie'}</div>
                    <button className="logout-btn" onClick={onLogout}>Abmelden</button>
                </div>
            </div>

            <div className="main">
                <div className="topbar">
                    <h2>{viewTitles[view] || ''}</h2>
                    <div className="topbar-actions">
                        {urgent > 0 && <span className="badge badge-red">{urgent} dringend</span>}
                        {summary.inbox_count > 0 && <span className="badge badge-purple">{summary.inbox_count} Inbox</span>}
                        <VoiceButton />
                    </div>
                </div>

                <div className="content">
                    <ViewTransition viewKey={view + (selectedProject || '')}>
                        {view === 'overview' && <OverviewView projects={projects} summary={summary} onSelect={id => { setSelectedProject(id); setView('detail'); }} />}
                        {view === 'projects' && <ProjectsView projects={projects} onSelect={id => { setSelectedProject(id); setView('detail'); }} />}
                        {view === 'tasks' && <TasksView projects={projects} onComplete={completeTask} />}
                        {view === 'chat' && <ChatView messages={chatMessages} setMessages={setChatMessages} onAction={reload} />}
                        {view === 'detail' && <DetailView project={projects.find(p => p.id === selectedProject)} onComplete={completeTask} />}
                        {view === 'activity' && <ActivityView projects={projects} />}
                    </ViewTransition>
                </div>

                {completedToast && (
                    <div className="toast">✓ {completedToast}</div>
                )}
            </div>

            <MobileBar view={view} setView={setView} setSelectedProject={setSelectedProject}
                taskCount={summary.total_open_tasks} inboxCount={summary.inbox_count} projects={projects} />
        </div>
    );
}

/* ---- Mobile Bottom Bar ---- */
function MobileBar({ view, setView, setSelectedProject, taskCount, inboxCount, projects }) {
    const [showMore, setShowMore] = useState(false);

    const go = (v) => { setView(v); setSelectedProject(null); setShowMore(false); };

    return (
        <>
            <div className="mobile-bar">
                <div className="mobile-bar-inner">
                    <button className={`mobile-tab ${view === 'overview' ? 'active' : ''}`} onClick={() => go('overview')}>
                        <span className="tab-icon">◉</span>
                        <span>Home</span>
                    </button>
                    <button className={`mobile-tab ${view === 'tasks' ? 'active' : ''}`} onClick={() => go('tasks')}>
                        <span className="tab-icon">☐</span>
                        <span>Tasks</span>
                        {taskCount > 0 && <span className="tab-badge">{taskCount > 99 ? '99+' : taskCount}</span>}
                    </button>
                    <button className={`mobile-tab ${view === 'chat' ? 'active' : ''}`} onClick={() => go('chat')}>
                        <span className="tab-icon">◈</span>
                        <span>Assistent</span>
                    </button>
                    <button className={`mobile-tab ${showMore ? 'active' : ''}`} onClick={() => setShowMore(!showMore)}>
                        <span className="tab-icon">≡</span>
                        <span>Mehr</span>
                        {inboxCount > 0 && <span className="tab-badge">{inboxCount}</span>}
                    </button>
                </div>
            </div>

            {showMore && (
                <div className="more-menu" onClick={(e) => { if (e.target === e.currentTarget) setShowMore(false); }}>
                    <div className="more-menu-inner">
                        <h3>Navigation</h3>
                        <button className="more-item" onClick={() => go('projects')}>
                            <span className="more-icon">▦</span> Projekte
                        </button>
                        <button className="more-item" onClick={() => go('activity')}>
                            <span className="more-icon">◷</span> Aktivitaet
                        </button>

                        <h3 style={{marginTop: 16}}>Projekte</h3>
                        {projects.map((p, i) => (
                            <button key={p.id} className="more-item" onClick={() => { setSelectedProject(p.id); setView('detail'); setShowMore(false); }}>
                                <span className="more-icon" style={{color: PROJECT_COLORS[i % PROJECT_COLORS.length]}}>●</span>
                                {p.name}
                                <span className="more-count">{p.open_count}</span>
                            </button>
                        ))}
                    </div>
                </div>
            )}
        </>
    );
}

/* ---- Voice / Recording Button ---- */
function VoiceButton() {
    const [recording, setRecording] = useState(false);
    const [showModal, setShowModal] = useState(false);
    const [status, setStatus] = useState('idle'); // idle, recording, uploading, done
    const [recordings, setRecordings] = useState([]);
    const [transcribing, setTranscribing] = useState(null);
    const mediaRef = useRef(null);
    const streamRef2 = useRef(null);
    const chunksRef = useRef([]);
    const recordStartRef = useRef(null);

    const loadRecordings = async () => {
        try {
            const res = await fetch(`${API}/api/recordings`);
            const data = await res.json();
            setRecordings(data.recordings || []);
        } catch {}
    };

    const startRecording = async () => {
        if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
            if (location.protocol !== 'https:' && location.hostname !== 'localhost') {
                alert('Mikrofon benoetigt HTTPS. Die App laeuft aktuell ueber HTTP.');
            } else {
                alert('Mikrofon nicht verfuegbar auf diesem Geraet.');
            }
            return;
        }
        try {
            const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
            streamRef2.current = stream;
            const mr = new MediaRecorder(stream);
            chunksRef.current = [];
            mr.ondataavailable = e => chunksRef.current.push(e.data);
            mr.onstop = async () => {
                // Release mic immediately (kills iOS orange dot)
                if (streamRef2.current) {
                    streamRef2.current.getTracks().forEach(t => t.stop());
                    streamRef2.current = null;
                }
                const duration = (Date.now() - recordStartRef.current) / 1000;
                if (duration < 3) {
                    setStatus('idle');
                    return; // Zu kurz — nicht speichern
                }
                const mimeType = mr.mimeType || 'audio/wav';
                const ext = mimeType.includes('webm') ? 'webm' : 'wav';
                const blob = new Blob(chunksRef.current, { type: mimeType });
                setStatus('uploading');
                const form = new FormData();
                form.append('file', blob, `meeting_${Date.now()}.${ext}`);
                try {
                    await fetch(`${API}/api/recordings/upload`, { method: 'POST', body: form });
                    setStatus('done');
                    loadRecordings();
                } catch { setStatus('idle'); }
            };
            mediaRef.current = mr;
            mr.start();
            recordStartRef.current = Date.now();
            setRecording(true);
            setStatus('recording');
            if (navigator.vibrate) navigator.vibrate(10);
        } catch (e) {
            if (e.name === 'NotAllowedError') {
                alert('Mikrofon-Zugriff verweigert. Bitte in den Browser-Einstellungen erlauben.');
            } else {
                alert('Mikrofon nicht verfuegbar: ' + e.message);
            }
        }
    };

    const stopRecording = () => {
        if (mediaRef.current && mediaRef.current.state !== 'inactive') {
            mediaRef.current.stop();
        }
        // Release mic immediately
        if (streamRef2.current) {
            streamRef2.current.getTracks().forEach(t => t.stop());
            streamRef2.current = null;
        }
        setRecording(false);
    };

    const transcribe = async (id) => {
        setTranscribing(id);
        try {
            await fetch(`${API}/api/recordings/${id}/transcribe`, { method: 'POST' });
            loadRecordings();
        } catch {}
        setTranscribing(null);
    };

    const openModal = () => { setShowModal(true); setStatus('idle'); loadRecordings(); };

    return (
        <>
            <button className="voice-btn" onClick={openModal} title="Meeting aufnehmen">🎙</button>
            {showModal && (
                <div className="voice-modal" onClick={(e) => { if (e.target === e.currentTarget && status !== 'recording') setShowModal(false); }}>
                    <div className="voice-modal-inner" style={{maxWidth: 480, width: '90%', maxHeight: '80vh', overflow: 'auto'}}>
                        <div style={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 20}}>
                            <h3 style={{fontSize: 16}}>Meeting / Gespraech aufnehmen</h3>
                            {status !== 'recording' && <button onClick={() => setShowModal(false)} style={{background: 'none', border: 'none', color: '#6b7280', fontSize: 18, cursor: 'pointer'}}>✕</button>}
                        </div>

                        {status === 'idle' && (
                            <button className="record-btn" onClick={startRecording}>
                                <span style={{fontSize: 28}}>🎙</span>
                                <span>Aufnahme starten</span>
                            </button>
                        )}
                        {status === 'recording' && (
                            <div style={{textAlign: 'center'}}>
                                <div className="voice-pulse"></div>
                                <p style={{marginBottom: 16}}>Aufnahme laeuft...</p>
                                <button className="voice-stop" onClick={stopRecording}>■ Stopp & Hochladen</button>
                            </div>
                        )}
                        {status === 'uploading' && <p style={{textAlign: 'center', color: '#6b7280'}}>Wird hochgeladen...</p>}
                        {status === 'done' && <p style={{textAlign: 'center', color: '#22c55e', marginBottom: 16}}>✓ Hochgeladen!</p>}

                        {recordings.length > 0 && (
                            <div style={{marginTop: 24, borderTop: '1px solid #2a2e3a', paddingTop: 16}}>
                                <h4 style={{fontSize: 13, color: '#6b7280', marginBottom: 12}}>Aufnahmen</h4>
                                {recordings.map(r => (
                                    <div key={r.id} className="recording-item">
                                        <div style={{flex: 1}}>
                                            <div style={{fontSize: 13}}>{r.filename}</div>
                                            <div style={{fontSize: 11, color: '#6b7280'}}>{new Date(r.created_at).toLocaleString('de-CH')}</div>
                                            {r.status === 'transcribed' && r.transcript && (
                                                <div style={{marginTop: 8, fontSize: 12, color: '#e4e4e7', background: '#1a1d27', padding: 10, borderRadius: 6}}>
                                                    <div style={{color: '#6b7280', marginBottom: 4}}>Transkript:</div>
                                                    {r.transcript.substring(0, 200)}{r.transcript.length > 200 ? '...' : ''}
                                                </div>
                                            )}
                                            {r.followups && (
                                                <div style={{marginTop: 8, fontSize: 12, color: '#22c55e', background: 'rgba(34,197,94,0.08)', padding: 10, borderRadius: 6}}>
                                                    <div style={{color: '#6b7280', marginBottom: 4}}>Follow-ups:</div>
                                                    {r.followups.split('\n').map((l, i) => <div key={i}>{l}</div>)}
                                                </div>
                                            )}
                                        </div>
                                        <div>
                                            {r.status === 'uploaded' && (
                                                <button className="filter-btn active" onClick={() => transcribe(r.id)}
                                                    disabled={transcribing === r.id} style={{whiteSpace: 'nowrap'}}>
                                                    {transcribing === r.id ? '...' : 'Transkribieren'}
                                                </button>
                                            )}
                                            {r.status === 'transcribed' && <span className="badge badge-green">Fertig</span>}
                                        </div>
                                    </div>
                                ))}
                            </div>
                        )}
                    </div>
                </div>
            )}
        </>
    );
}

/* ---- Eisenhower Chart ---- */
function OverviewView({ projects, summary, onSelect }) {
    const canvasRef = useRef(null);
    const chartRef = useRef(null);
    const [mode, setMode] = useState('projects'); // 'projects' or 'tasks'
    const [filterProject, setFilterProject] = useState('all');

    useEffect(() => {
        if (!canvasRef.current) return;
        if (chartRef.current) chartRef.current.destroy();

        let points = [];

        if (mode === 'projects') {
            const maxTasks = Math.max(...projects.map(p => p.open_count), 1);
            points = projects.map((p, i) => {
                const urgency = calcUrgency(p);
                const radius = 10 + (p.open_count / maxTasks) * 28;
                const color = PROJECT_COLORS[i % PROJECT_COLORS.length];
                return { x: urgency, y: p.importance, r: radius, label: shortName(p.name), color, id: p.id, info: `${p.open_count} Tasks` };
            });
        } else {
            // Tasks mode
            const allTasks = [];
            projects.forEach((proj, pi) => {
                if (filterProject !== 'all' && proj.id !== filterProject) return;
                const ids = proj.task_ids || [];
                proj.open_tasks.forEach((task, ti) => {
                    allTasks.push({
                        text: task, projectName: proj.name, importance: proj.importance,
                        urgency: calcUrgency(proj), color: PROJECT_COLORS[pi % PROJECT_COLORS.length],
                        id: ids[ti],
                    });
                });
            });
            points = allTasks.map(t => ({
                x: t.urgency + (Math.random() - 0.5) * 0.8,
                y: t.importance + (Math.random() - 0.5) * 0.6,
                r: 6, label: '', color: t.color, id: t.id,
                info: t.text.substring(0, 50),
            }));
        }

        chartRef.current = new Chart(canvasRef.current, {
            type: 'bubble',
            data: {
                datasets: [{
                    data: points,
                    backgroundColor: points.map(p => p.color + '50'),
                    borderColor: points.map(p => p.color),
                    borderWidth: 2,
                    hoverBorderWidth: 3,
                }]
            },
            options: {
                responsive: true,
                maintainAspectRatio: false,
                animation: { duration: 300 },
                onClick: (evt, elements) => {
                    if (elements.length > 0 && mode === 'projects') {
                        const idx = elements[0].index;
                        if (points[idx].id) onSelect(points[idx].id);
                    }
                },
                scales: {
                    x: {
                        min: 0, max: 11,
                        title: { display: true, text: 'Dringlichkeit  →', color: '#6b7280', font: { size: 12 } },
                        ticks: { display: false },
                        grid: { color: '#1a1d27' },
                        border: { color: '#2a2e3a' },
                    },
                    y: {
                        min: 0, max: 11,
                        title: { display: true, text: '↑  Wichtigkeit', color: '#6b7280', font: { size: 12 } },
                        ticks: { display: false },
                        grid: { color: '#1a1d27' },
                        border: { color: '#2a2e3a' },
                    },
                },
                plugins: {
                    legend: { display: false },
                    tooltip: {
                        callbacks: {
                            title: () => '',
                            label: ctx => {
                                const p = points[ctx.dataIndex];
                                return p.label ? `${p.label} — ${p.info}` : p.info;
                            }
                        },
                        backgroundColor: '#1c2029',
                        borderColor: '#2a2e3a',
                        borderWidth: 1,
                        padding: 10,
                    },
                    datalabels: {
                        display: mode === 'projects',
                        color: '#e4e4e7',
                        font: { size: 11, weight: 500 },
                        anchor: 'end', align: 'top', offset: 4,
                        formatter: (val, ctx) => points[ctx.dataIndex].label,
                    },
                },
            },
            plugins: [ChartDataLabels, {
                afterDraw: (chart) => {
                    const { ctx, chartArea: { left, right, top, bottom } } = chart;
                    const midX = (left + right) / 2;
                    const midY = (top + bottom) / 2;
                    ctx.save();
                    ctx.font = '600 11px system-ui';
                    ctx.fillStyle = '#1f2233';
                    ctx.textAlign = 'center';
                    ctx.fillText('PLANEN', (left + midX) / 2, top + 20);
                    ctx.fillText('SOFORT', (midX + right) / 2, top + 20);
                    ctx.fillText('ELIMINIEREN', (left + midX) / 2, bottom - 10);
                    ctx.fillText('DELEGIEREN', (midX + right) / 2, bottom - 10);
                    ctx.strokeStyle = '#1f2233';
                    ctx.setLineDash([4, 4]);
                    ctx.beginPath();
                    ctx.moveTo(midX, top); ctx.lineTo(midX, bottom);
                    ctx.moveTo(left, midY); ctx.lineTo(right, midY);
                    ctx.stroke();
                    ctx.restore();
                }
            }],
        });

        return () => { if (chartRef.current) chartRef.current.destroy(); };
    }, [projects, mode, filterProject]);

    return (
        <>
            <div className="summary-row">
                <div className="stat-card">
                    <div className="label">Projekte</div>
                    <div className="value">{summary.total_projects}</div>
                </div>
                <div className="stat-card">
                    <div className="label">Offene Tasks</div>
                    <div className="value">{summary.total_open_tasks}</div>
                </div>
                <div className="stat-card">
                    <div className="label">Dringend</div>
                    <div className="value" style={{color: projects.filter(p => p.overdue || (p.days_left !== null && p.days_left <= 7)).length > 0 ? COLORS.red : COLORS.green}}>
                        {projects.filter(p => p.overdue || (p.days_left !== null && p.days_left <= 7)).length}
                    </div>
                </div>
                <div className="stat-card">
                    <div className="label">Inbox</div>
                    <div className="value">{summary.inbox_count}</div>
                </div>
            </div>

            <div style={{display: 'flex', gap: 8, marginBottom: 12, flexWrap: 'wrap'}}>
                <button className={`filter-btn ${mode === 'projects' ? 'active' : ''}`} onClick={() => setMode('projects')}>Projekte</button>
                <button className={`filter-btn ${mode === 'tasks' ? 'active' : ''}`} onClick={() => setMode('tasks')}>Tasks</button>
                {mode === 'tasks' && (
                    <>
                        <span style={{color: '#2a2e3a', margin: '0 4px'}}>|</span>
                        <button className={`filter-btn ${filterProject === 'all' ? 'active' : ''}`} onClick={() => setFilterProject('all')}>Alle</button>
                        {projects.map((p, i) => (
                            <button key={p.id} className={`filter-btn ${filterProject === p.id ? 'active' : ''}`}
                                onClick={() => setFilterProject(p.id)}
                                style={filterProject === p.id ? {} : {borderColor: PROJECT_COLORS[i % PROJECT_COLORS.length] + '60'}}>
                                {shortName(p.name)}
                            </button>
                        ))}
                    </>
                )}
            </div>

            <div className="chart-container">
                <canvas ref={canvasRef}></canvas>
            </div>

            <div className="chart-legend">
                {projects.map((p, i) => (
                    <div className="legend-item" key={p.id}>
                        <div className="legend-dot" style={{background: PROJECT_COLORS[i % PROJECT_COLORS.length]}}></div>
                        {shortName(p.name)}
                    </div>
                ))}
                {mode === 'projects' && <div className="legend-item" style={{marginLeft: 12}}>Groesse = Anzahl Tasks</div>}
            </div>
        </>
    );
}

/* ---- Projects List ---- */
function ProjectsView({ projects, onSelect }) {
    return (
        <div className="project-list">
            <div className="project-row" style={{background: 'transparent', border: 'none', cursor: 'default', fontSize: 11, color: '#6b7280', textTransform: 'uppercase', letterSpacing: '0.5px'}}>
                <div></div>
                <div>Projekt</div>
                <div>Prioritaet</div>
                <div>Deadline</div>
                <div>Status</div>
                <div>Tasks</div>
            </div>
            {projects.map((p, i) => {
                const color = PROJECT_COLORS[i % PROJECT_COLORS.length];
                const impLabel = p.importance >= 9 ? 'Kritisch' : p.importance >= 7 ? 'Hoch' : 'Normal';
                const impClass = p.importance >= 9 ? 'badge-red' : p.importance >= 7 ? 'badge-orange' : 'badge-green';
                let dueLabel = '--';
                let dueClass = '';
                if (p.overdue) { dueLabel = 'Ueberfaellig'; dueClass = 'badge-red'; }
                else if (p.days_left !== null && p.days_left <= 7) { dueLabel = p.days_left + 'd'; dueClass = 'badge-red'; }
                else if (p.days_left !== null && p.days_left <= 30) { dueLabel = p.days_left + 'd'; dueClass = 'badge-orange'; }
                else if (p.due && p.due !== 'None') { dueLabel = p.due; dueClass = 'badge-blue'; }

                return (
                    <div className="project-row" key={p.id} onClick={() => onSelect(p.id)}>
                        <div className="indicator" style={{background: color}}></div>
                        <div className="name">{p.name}</div>
                        <span className={`badge ${impClass}`}>{impLabel}</span>
                        <span className={`badge ${dueClass}`}>{dueLabel}</span>
                        <span className="meta">{p.status}</span>
                        <span className="meta" style={{fontWeight: 600, fontSize: 15}}>{p.open_count}</span>
                    </div>
                );
            })}
        </div>
    );
}

/* ---- Task Row with inline edit ---- */
function TaskRow({ item, onComplete, formatDate }) {
    const [editing, setEditing] = useState(false);
    const [editText, setEditText] = useState(item.task);
    const [saving, setSaving] = useState(false);

    const save = async () => {
        if (!editText.trim() || editText === item.task) { setEditing(false); return; }
        setSaving(true);
        try {
            await fetch(`${API}/api/tasks/${item.taskId}/edit`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ text: editText.trim() }),
            });
            item.task = editText.trim();
        } catch {}
        setSaving(false);
        setEditing(false);
    };

    return (
        <div className="task-row">
            <div className="task-checkbox" onClick={(e) => { e.stopPropagation(); onComplete(item.taskId, e.target); }}
                 title="Als erledigt markieren"></div>
            <div style={{minWidth: 0}}>
                {editing ? (
                    <div style={{display: 'flex', gap: 6}}>
                        <input className="chat-input" value={editText} onChange={e => setEditText(e.target.value)}
                            onKeyDown={e => { if (e.key === 'Enter') save(); if (e.key === 'Escape') setEditing(false); }}
                            autoFocus style={{fontSize: 13, padding: '4px 8px'}} />
                        <button className="filter-btn active" onClick={save} disabled={saving} style={{padding: '4px 10px', fontSize: 11}}>
                            {saving ? '...' : 'OK'}
                        </button>
                    </div>
                ) : (
                    <div onClick={() => setEditing(true)} style={{cursor: 'text'}}>
                        <div style={{display: 'flex', gap: 6, alignItems: 'center'}}>
                            {item.displayId && <span style={{fontSize: 11, color: '#6366f1', fontWeight: 600, flexShrink: 0}}>{item.displayId}</span>}
                            <span>{item.task}</span>
                        </div>
                        {item.createdAt && <div style={{fontSize: 11, color: '#6b7280', marginTop: 2}}>{formatDate(item.createdAt)}</div>}
                    </div>
                )}
            </div>
            <span className="task-project-tag" style={{borderColor: item.color + '40', color: item.color}}>
                {shortName(item.projectName)}
            </span>
        </div>
    );
}

/* ---- All Tasks ---- */
function TasksView({ projects, onComplete }) {
    const [filter, setFilter] = useState('all');
    const [projectFilter, setProjectFilter] = useState('all');
    const [search, setSearch] = useState('');
    const [sort, setSort] = useState('newest'); // 'newest', 'oldest', 'importance'

    const allTasks = [];
    projects.forEach((proj, pi) => {
        const ids = proj.task_ids || [];
        const dids = proj.task_display_ids || [];
        const dates = proj.task_dates || [];
        proj.open_tasks.forEach((task, idx) => {
            allTasks.push({ task, taskId: ids[idx], displayId: dids[idx] || '', createdAt: dates[idx] || '', projectName: proj.name, projectId: proj.id, importance: proj.importance, color: PROJECT_COLORS[pi % PROJECT_COLORS.length] });
        });
    });

    let filtered = allTasks;
    if (filter === 'critical') filtered = filtered.filter(t => t.importance >= 9);
    else if (filter === 'high') filtered = filtered.filter(t => t.importance >= 7);
    if (projectFilter !== 'all') filtered = filtered.filter(t => t.projectId === projectFilter);
    if (search) filtered = filtered.filter(t => t.task.toLowerCase().includes(search.toLowerCase()));

    // Sort
    filtered = [...filtered].sort((a, b) => {
        if (sort === 'newest') return (b.createdAt || '').localeCompare(a.createdAt || '');
        if (sort === 'oldest') return (a.createdAt || '').localeCompare(b.createdAt || '');
        return b.importance - a.importance; // importance
    });

    const formatDate = (d) => {
        if (!d) return '';
        try {
            const dt = new Date(d);
            const now = new Date();
            const diff = Math.floor((now - dt) / 86400000);
            if (diff === 0) return 'Heute';
            if (diff === 1) return 'Gestern';
            if (diff < 7) return `vor ${diff}d`;
            return dt.toLocaleDateString('de-CH', { day: '2-digit', month: '2-digit' });
        } catch { return ''; }
    };

    return (
        <>
            <div style={{display: 'flex', gap: 8, marginBottom: 12, flexWrap: 'wrap', alignItems: 'center'}}>
                {['all', 'critical', 'high'].map(f => (
                    <button key={f} className={`filter-btn ${filter === f ? 'active' : ''}`} onClick={() => setFilter(f)}>
                        {f === 'all' ? `Alle (${allTasks.length})` : f === 'critical' ? 'Kritisch' : 'Hoch'}
                    </button>
                ))}
                <span style={{color: '#2a2e3a'}}>|</span>
                <button className={`filter-btn ${projectFilter === 'all' ? 'active' : ''}`} onClick={() => setProjectFilter('all')}>Alle Projekte</button>
                {projects.map((p, i) => (
                    <button key={p.id} className={`filter-btn ${projectFilter === p.id ? 'active' : ''}`} onClick={() => setProjectFilter(p.id)}>
                        {shortName(p.name)}
                    </button>
                ))}
                <span style={{color: '#2a2e3a'}}>|</span>
                {[['newest', 'Neueste'], ['oldest', 'Aelteste'], ['importance', 'Wichtigkeit']].map(([s, label]) => (
                    <button key={s} className={`filter-btn ${sort === s ? 'active' : ''}`} onClick={() => setSort(s)}>{label}</button>
                ))}
            </div>
            <input className="search-input" placeholder="Tasks durchsuchen..." value={search} onChange={e => setSearch(e.target.value)} />
            <div style={{fontSize: 12, color: '#6b7280', margin: '8px 0 12px'}}>{filtered.length} Tasks</div>
            <div className="task-list">
                {filtered.map((item, i) => (
                    <TaskRow key={item.taskId || i} item={item} onComplete={onComplete} formatDate={formatDate} />
                ))}
            </div>
        </>
    );
}

/* ---- Project Detail ---- */
function DetailView({ project, onComplete }) {
    if (!project) return <p>Projekt nicht gefunden.</p>;
    const ids = project.task_ids || [];
    const dids = project.task_display_ids || [];
    const dates = project.task_dates || [];

    const formatDate = (d) => {
        if (!d) return '';
        try {
            const dt = new Date(d);
            const now = new Date();
            const diff = Math.floor((now - dt) / 86400000);
            if (diff === 0) return 'Heute';
            if (diff === 1) return 'Gestern';
            if (diff < 7) return `vor ${diff}d`;
            return dt.toLocaleDateString('de-CH', { day: '2-digit', month: '2-digit' });
        } catch { return ''; }
    };

    return (
        <>
            <div className="detail-header">
                <h3>{project.name} {project.short_code && <span style={{fontSize: 14, color: '#6366f1', fontWeight: 400}}>({project.short_code})</span>}</h3>
                <div className="detail-meta">
                    <span className={`badge ${project.importance >= 9 ? 'badge-red' : project.importance >= 7 ? 'badge-orange' : 'badge-green'}`}>
                        Imp: {project.importance}/10
                    </span>
                    <span className="badge badge-blue">{project.status}</span>
                    {project.due && project.due !== 'None' && (
                        <span className={`badge ${project.overdue ? 'badge-red' : 'badge-orange'}`}>
                            {project.overdue ? 'Ueberfaellig' : `${project.days_left}d (${project.due})`}
                        </span>
                    )}
                    <span className="badge badge-purple">{project.open_count} Tasks</span>
                </div>
            </div>
            {project.sub_projects && project.sub_projects.length > 0 && (
                <div style={{marginBottom: 20}}>
                    <h4 style={{fontSize: 13, color: '#6b7280', marginBottom: 8}}>Sub-Projekte</h4>
                    <div className="summary-row" style={{gridTemplateColumns: 'repeat(auto-fill, minmax(160px, 1fr))'}}>
                        {project.sub_projects.map(sp => (
                            <div className="stat-card" key={sp.id} style={{cursor: 'pointer', borderLeft: '3px solid var(--accent)'}}
                                onClick={() => { onComplete._setProject && onComplete._setProject(sp.id); }}>
                                <div className="label">{sp.short_code}</div>
                                <div style={{fontSize: 14, fontWeight: 500}}>{sp.name}</div>
                                <div className="sub">{sp.open_count} Tasks</div>
                            </div>
                        ))}
                    </div>
                </div>
            )}
            <div className="detail-tasks">
                {project.open_tasks.length > 0 && project.sub_projects && project.sub_projects.length > 0 && (
                    <h4 style={{fontSize: 13, color: '#6b7280', marginBottom: 8}}>Direkte Tasks</h4>
                )}
                {project.open_tasks.map((task, i) => (
                    <TaskRow key={ids[i] || i} item={{
                        task, taskId: ids[i], displayId: dids[i] || '', createdAt: dates[i] || '',
                        projectName: project.name, color: '#6366f1'
                    }} onComplete={onComplete} formatDate={formatDate} />
                ))}
                {project.open_tasks.length === 0 && (!project.sub_projects || project.sub_projects.length === 0) && (
                    <p style={{color: '#6b7280', padding: 16}}>Keine offenen Tasks!</p>
                )}
            </div>
        </>
    );
}

/* ---- Activity View ---- */
function ActivityView({ projects }) {
    const totalTasks = projects.reduce((sum, p) => sum + p.open_count, 0);
    const tasksByProject = projects.map((p, i) => ({
        name: shortName(p.name),
        count: p.open_count,
        pct: Math.round((p.open_count / totalTasks) * 100),
        color: PROJECT_COLORS[i % PROJECT_COLORS.length],
    }));

    return (
        <>
            <div style={{marginBottom: 24}}>
                <h3 style={{fontSize: 14, color: '#6b7280', marginBottom: 12}}>Task-Verteilung nach Projekt</h3>
                <div className="bar-chart">
                    {tasksByProject.map((p, i) => (
                        <div key={i} style={{marginBottom: 12}}>
                            <div style={{display: 'flex', justifyContent: 'space-between', fontSize: 13, marginBottom: 4}}>
                                <span>{p.name}</span>
                                <span style={{color: '#6b7280'}}>{p.count} ({p.pct}%)</span>
                            </div>
                            <div style={{height: 8, background: '#1a1d27', borderRadius: 4, overflow: 'hidden'}}>
                                <div style={{height: '100%', width: `${p.pct}%`, background: p.color, borderRadius: 4, transition: 'width 0.5s'}}></div>
                            </div>
                        </div>
                    ))}
                </div>
            </div>

            <div style={{marginBottom: 24}}>
                <h3 style={{fontSize: 14, color: '#6b7280', marginBottom: 12}}>Projekt-Steckbriefe</h3>
                <div className="summary-row">
                    {projects.map((p, i) => (
                        <div className="stat-card" key={p.id} style={{borderLeft: `3px solid ${PROJECT_COLORS[i % PROJECT_COLORS.length]}`}}>
                            <div className="label">{shortName(p.name)}</div>
                            <div className="value" style={{fontSize: 24}}>{p.open_count}</div>
                            <div className="sub">
                                Imp: {p.importance}/10
                                {p.due && p.due !== 'None' ? ` · ${p.days_left}d` : ''}
                            </div>
                        </div>
                    ))}
                </div>
            </div>

            <div>
                <h3 style={{fontSize: 14, color: '#6b7280', marginBottom: 12}}>Quick Stats</h3>
                <div className="summary-row">
                    <div className="stat-card">
                        <div className="label">Kritische Projekte</div>
                        <div className="value" style={{color: COLORS.red}}>{projects.filter(p => p.importance >= 9).length}</div>
                    </div>
                    <div className="stat-card">
                        <div className="label">Mit Deadline</div>
                        <div className="value">{projects.filter(p => p.due && p.due !== 'None').length}</div>
                    </div>
                    <div className="stat-card">
                        <div className="label">Ohne Deadline</div>
                        <div className="value">{projects.filter(p => !p.due || p.due === 'None').length}</div>
                    </div>
                    <div className="stat-card">
                        <div className="label">Groesstes Projekt</div>
                        <div className="value" style={{fontSize: 16}}>{projects.reduce((a, b) => a.open_count > b.open_count ? a : b).name.split(' ').slice(0, 2).join(' ')}</div>
                    </div>
                </div>
            </div>
        </>
    );
}

/* ---- Voice Chat Button (Speech-to-Text) ---- */
function VoiceChatButton({ onTranscript, disabled }) {
    const [listening, setListening] = useState(false);
    const [processing, setProcessing] = useState(false);
    const mediaRef = useRef(null);
    const streamRef = useRef(null);
    const chunksRef = useRef([]);

    const hasMediaDevices = !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia);

    const stopListening = useCallback(() => {
        // Stop MediaRecorder
        if (mediaRef.current && mediaRef.current.state !== 'inactive') {
            mediaRef.current.stop();
        }
        // Immediately release microphone (kills iOS orange dot)
        if (streamRef.current) {
            streamRef.current.getTracks().forEach(t => t.stop());
            streamRef.current = null;
        }
        setListening(false);
    }, []);

    const startListening = async () => {
        if (listening) {
            stopListening();
            return;
        }

        if (!hasMediaDevices) {
            alert('Mikrofon nicht verfuegbar. HTTPS wird benoetigt.');
            return;
        }

        try {
            const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
            streamRef.current = stream;
            const mr = new MediaRecorder(stream);
            chunksRef.current = [];
            mr.ondataavailable = e => chunksRef.current.push(e.data);
            mr.onstop = async () => {
                // Release mic immediately
                if (streamRef.current) {
                    streamRef.current.getTracks().forEach(t => t.stop());
                    streamRef.current = null;
                }
                const mimeType = mr.mimeType || 'audio/wav';
                const ext = mimeType.includes('webm') ? 'webm' : 'wav';
                const blob = new Blob(chunksRef.current, { type: mimeType });
                setListening(false);
                setProcessing(true);
                try {
                    const form = new FormData();
                    form.append('file', blob, `voice.${ext}`);
                    const res = await fetch(`${API}/api/speech-to-text`, { method: 'POST', body: form });
                    const data = await res.json();
                    if (data.ok && data.text) {
                        onTranscript(data.text);
                    } else {
                        alert('Spracherkennung fehlgeschlagen: ' + (data.error || 'Kein Text erkannt'));
                    }
                } catch {
                    alert('Fehler bei der Spracherkennung');
                }
                setProcessing(false);
            };
            mediaRef.current = mr;
            mr.start();
            setListening(true);
            if (navigator.vibrate) navigator.vibrate(10);
        } catch (e) {
            // Release mic on error too
            if (streamRef.current) {
                streamRef.current.getTracks().forEach(t => t.stop());
                streamRef.current = null;
            }
            if (e.name === 'NotAllowedError') {
                alert('Mikrofon-Zugriff verweigert. Bitte in den Einstellungen erlauben.');
            } else {
                alert('Mikrofon nicht verfuegbar: ' + e.message);
            }
        }
    };

    return (
        <button
            className={`voice-chat-btn ${listening ? 'listening' : ''}`}
            onClick={startListening}
            disabled={disabled || processing}
            title={listening ? 'Aufnahme stoppen' : 'Spracheingabe'}
        >
            {processing ? '...' : listening ? '■' : '🎙'}
        </button>
    );
}

/* ---- Chat ---- */
function ChatView({ messages, setMessages, onAction }) {
    const [input, setInput] = useState('');
    const [sending, setSending] = useState(false);
    const bottomRef = useRef(null);

    useEffect(() => {
        bottomRef.current?.scrollIntoView({ behavior: 'smooth' });
    }, [messages]);

    const send = async (text) => {
        const msg = text || input.trim();
        if (!msg || sending) return;
        setInput('');
        setMessages(prev => [...prev, { role: 'user', text: msg }]);
        setSending(true);

        try {
            const res = await fetch(`${API}/api/chat`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ message: msg }),
            });
            const data = await res.json();
            setMessages(prev => [...prev, { role: 'bot', text: data.reply || 'Keine Antwort.' }]);
            // Refresh dashboard data after bot action (task created, completed, etc.)
            if (onAction) onAction();
        } catch {
            setMessages(prev => [...prev, { role: 'bot', text: 'Fehler bei der Verbindung.' }]);
        }
        setSending(false);
    };

    return (
        <div className="chat-panel">
            <div className="chat-messages">
                {messages.map((msg, i) => (
                    <div key={i} className={`chat-msg ${msg.role === 'user' ? 'user' : 'bot'}`}>
                        {msg.text.split('\n').map((line, j) => <span key={j}>{line}<br/></span>)}
                    </div>
                ))}
                {sending && <div className="chat-msg bot" style={{opacity: 0.5}}>Denke nach...</div>}
                <div ref={bottomRef}></div>
            </div>
            <div className="chat-input-row">
                <input
                    className="chat-input"
                    value={input}
                    onChange={e => setInput(e.target.value)}
                    onKeyDown={e => e.key === 'Enter' && send()}
                    placeholder="Frag mich was..."
                />
                <VoiceChatButton onTranscript={(text) => { setInput(text); }} disabled={sending} />
                <button className="chat-send" onClick={() => send()}>Senden</button>
            </div>
        </div>
    );
}

/* ---- Helpers ---- */
function calcUrgency(p) {
    if (p.overdue) return 10;
    if (p.days_left === null) return 3;
    if (p.days_left <= 0) return 10;
    if (p.days_left <= 7) return 9;
    if (p.days_left <= 14) return 8;
    if (p.days_left <= 30) return 7;
    if (p.days_left <= 60) return 5;
    if (p.days_left <= 90) return 4;
    return 2;
}

function shortName(name) {
    const words = name.split(/[\s\-]+/);
    return words.length > 3 ? words.slice(0, 3).join(' ') : name;
}

ReactDOM.createRoot(document.getElementById("app")).render(<Root />);
