import { RedwebClient } from 'redweb-client';
import { match, type Snapshot } from './contract.js';

const client = new RedwebClient('/match', { version: '1', maxQueueSize: 0,
    reconnect: { enabled: true, maxAttempts: 8 },
});
const protocol = match.client({ send: frame => client.sendRaw(frame) });
const form = document.querySelector<HTMLFormElement>('#join')!;
const status = document.querySelector<HTMLElement>('#status')!;
const connection = document.querySelector<HTMLElement>('#connection')!;
const notice = document.querySelector<HTMLElement>('#notice')!;
const cells = [...document.querySelectorAll<HTMLButtonElement>('[data-cell]')];
let state: Snapshot | undefined;
let synchronized = false;

function render() {
    for (const [index, button] of cells.entries()) {
        button.textContent = state?.board[index] ?? '·';
        button.disabled = !state || !synchronized || client.state !== 'open' || state.players.length !== 2 ||
            Boolean(state.result) || state.you !== state.turn || state.board[index] !== null;
    }
    if (state) {
        const outcome = state.result === 'draw' ? 'Draw!' : state.result ? `${state.result} wins!` : `Turn: ${state.turn}`;
        status.textContent = `Room ${state.room} · You: ${state.you} · ${outcome} · Online: ${state.online.join(', ')}`;
        form.hidden = true;
    }
}
async function send(operation: () => Promise<unknown>) {
    try {
        if (client.state !== 'open') throw new Error('Wait for the connection, then try again.');
        await operation();
    } catch (error) { notice.textContent = (error as Error).message; }
}
client.onAny(message => { void protocol.parse(JSON.stringify(message)).then(event => {
    if (event.type === 'state') { state = event.payload; synchronized = true; notice.textContent = ''; render(); }
    else if (event.type === 'notice') notice.textContent = event.payload.text;
    else if (event.type === 'error') notice.textContent = event.error.message;
}).catch(() => { notice.textContent = 'Invalid server response. Reload the page.'; }); });
client.onStateChange(value => {
    synchronized = false;
    connection.textContent = value === 'open' ? 'Connected' : `${value} — moves are paused`;
    render();
    if (value === 'open' && state) void send(() => protocol.send('resume', { room: state!.room }));
});
client.onError(() => { notice.textContent = 'Connection unavailable. If signed out, sign in again.'; });
form.addEventListener('submit', event => {
    event.preventDefault();
    void send(() => protocol.send('join', { room: String(new FormData(form).get('room')) }));
});
for (const [cell, button] of cells.entries()) button.addEventListener('click', () => {
    if (state) void send(() => protocol.send('move', { cell, revision: state!.revision }));
});
window.addEventListener('pagehide', () => client.dispose(), { once: true });
void client.connect().catch(() => { notice.textContent = 'Unable to connect. Sign in again or reload.'; });
