import { useEffect, useRef, useState } from 'react';
const BASE = 'http://localhost:8082';

export default function App() {
  const [session, setSession] = useState(null);
  const [mode, setMode] = useState('login');
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [todos, setTodos] = useState([]);
  const [title, setTitle] = useState('');
  const [editing, setEditing] = useState(null);
  const [completed, setCompleted] = useState(false);
  const [message, setMessage] = useState('');
  const [busy, setBusy] = useState(false);
  const sessionRef = useRef(null);
  function loginSession(value) { sessionRef.current = value; setSession(value); }
  function logout() {
    sessionRef.current = null; setSession(null); setTodos([]); setTitle('');
    setEditing(null); setCompleted(false); setPassword('');
  }
  async function api(route, method = 'GET', body, current = sessionRef.current) {
    const response = await fetch(BASE + route, {
      method,
      headers: {
        ...(body !== undefined ? { 'Content-Type': 'application/json' } : {}),
        ...(current ? { Authorization: 'Bearer ' + current.accessToken } : {})
      },
      ...(body !== undefined ? { body: JSON.stringify(body) } : {})
    });
    const text = await response.text();
    let data = {}; try { data = text ? JSON.parse(text) : {}; } catch { data = { message: text }; }
    if (!response.ok) {
      if (response.status === 401 && current && sessionRef.current === current) logout();
      const details = data.details ? Object.entries(data.details).map(([k,v]) => k + ': ' + v).join('; ') : '';
      throw new Error([data.message || ('HTTP ' + response.status), details].filter(Boolean).join(' — '));
    }
    return data;
  }
  async function refresh(current = sessionRef.current) {
    const items = await api('/api/todos', 'GET', undefined, current);
    if (sessionRef.current === current) setTodos(items);
  }
  useEffect(() => {
    if (!session) return;
    const remaining = session.expiresAt - Date.now();
    const timeout = setTimeout(() => { logout(); setMessage('Session expired. Sign in again.'); }, Math.max(0, remaining));
    return () => clearTimeout(timeout);
  }, [session]);
  async function authenticate(event) {
    event.preventDefault(); setBusy(true); setMessage('');
    try {
      if (mode === 'register') {
        await api('/api/auth/register', 'POST', { email, password }, null);
        setMode('login'); setPassword(''); setMessage('Registered. Sign in with your password.');
      } else {
        const data = await api('/api/auth/login', 'POST', { email, password }, null);
        const current = { ...data, expiresAt: Date.now() + data.expiresIn * 1000 };
        loginSession(current); setPassword(''); await refresh(current);
      }
    } catch (error) { setMessage(error.message); } finally { setBusy(false); }
  }
  async function save(event) {
    event.preventDefault(); setBusy(true); setMessage('');
    try {
      await api(editing ? '/api/todos/' + editing : '/api/todos', editing ? 'PUT' : 'POST', { title, completed });
      setTitle(''); setCompleted(false); setEditing(null); await refresh();
    } catch (error) { setMessage(error.message); } finally { setBusy(false); }
  }
  async function remove(id) {
    setBusy(true); setMessage('');
    try {
      await api('/api/todos/' + id, 'DELETE');
      if (editing === id) { setEditing(null); setTitle(''); setCompleted(false); }
      await refresh();
    } catch (error) { setMessage(error.message); } finally { setBusy(false); }
  }
  return <main>
    <h1>My personal todos</h1>
    <p role="status">{message}</p>
    {!session ? <>
      <h2>{mode === 'login' ? 'Sign in' : 'Register'}</h2>
      <form onSubmit={authenticate}>
        <label>Email<input type="email" required maxLength={254} value={email} onChange={e => setEmail(e.target.value)} autoComplete="username" /></label>
        <label>Password<input type="password" required minLength={8} maxLength={72} value={password} onChange={e => setPassword(e.target.value)} autoComplete={mode === 'login' ? 'current-password' : 'new-password'} /></label>
        <button disabled={busy}>{busy ? 'Please wait…' : mode === 'login' ? 'Sign in' : 'Create account'}</button>
      </form>
      <button disabled={busy} onClick={() => { setMode(mode === 'login' ? 'register' : 'login'); setMessage(''); setPassword(''); }}>
        {mode === 'login' ? 'Need an account? Register' : 'Already registered? Sign in'}
      </button>
    </> : <>
      <p>Signed in as {session.email}</p><button disabled={busy} onClick={() => { logout(); setMessage('Signed out.'); }}>Sign out</button>
      <h2>{editing ? 'Edit todo' : 'Add todo'}</h2>
      <form onSubmit={save}>
        <label>Title<input required maxLength={120} value={title} onChange={e => setTitle(e.target.value)} /></label>
        <label><input type="checkbox" checked={completed} onChange={e => setCompleted(e.target.checked)} /> Completed</label>
        <button disabled={busy}>Save</button>
        {editing && <button type="button" disabled={busy} onClick={() => { setEditing(null); setTitle(''); setCompleted(false); }}>Cancel</button>}
      </form>
      <button disabled={busy} onClick={async () => { setBusy(true); try { await refresh(); setMessage(''); } catch(e) { setMessage(e.message); } finally { setBusy(false); } }}>Refresh</button>
      {todos.length === 0 ? <p>No tasks yet.</p> : <ul>{todos.map(todo => <li key={todo.id}>
        <span>{todo.title} — {todo.completed ? 'Done' : 'Pending'}</span>
        <button disabled={busy} onClick={() => { setEditing(todo.id); setTitle(todo.title); setCompleted(todo.completed); }}>Edit</button>
        <button disabled={busy} onClick={() => remove(todo.id)}>Delete</button>
      </li>)}</ul>}
    </>}
  </main>;
}
