const USERNAME_KEY = 'scrumPoker.username';
const PRESETS_KEY = 'scrumPoker.deckPresets.v1';

const SCALE_PRESETS = {
    fibonacci: ['0', '1', '2', '3', '5', '8', '13', '21', '?'],
    tshirt: ['XS', 'S', 'M', 'L', 'XL', '?'],
    'powers-of-two': ['1', '2', '4', '8', '16', '32', '?'],
};

const SPECIAL_CARD_ORDER = {
    '?': 1,
    '∞': 2,
    '☕': 3,
};

const roomConfigForm = document.getElementById('room-config-form');
const statusLine = document.getElementById('config-status');
const scaleSelect = document.getElementById('estimation-scale');
const maxPeopleInput = document.getElementById('max-people');
const previewScale = document.getElementById('preview-scale');
const previewMaxPeople = document.getElementById('preview-max-people');
const previewCards = document.getElementById('preview-cards');
const customCardInput = document.getElementById('custom-card');
const addCardButton = document.getElementById('add-card');
const autoSortButton = document.getElementById('auto-sort');
const usernameInput = document.getElementById('username');

const savePresetButton = document.getElementById('save-preset');
const pickerToggleButton = document.getElementById('preset-picker-toggle');
const shareDeckButton = document.getElementById('share-deck');
const presetModalOverlay = document.getElementById('preset-modal-overlay');
const presetModalCloseButton = document.getElementById('preset-modal-close');
const presetModalDoneButton = document.getElementById('preset-modal-done');
const presetList = document.getElementById('preset-list');
const importToggleButton = document.getElementById('import-toggle');
const importPane = document.getElementById('import-pane');
const importInput = document.getElementById('import-b64');
const importApplyButton = document.getElementById('import-apply');
let nextCardID = 1;
let currentCards = [];
let draggingCardID = '';
let draggedElement = null;
let deckPresets = loadPresets();

const savedUsername = localStorage.getItem(USERNAME_KEY);
if (savedUsername && !usernameInput.value) {
    usernameInput.value = savedUsername;
}

if (!window.CardUI || typeof window.CardUI.appendFace !== 'function') {
    throw new Error('CardUI is not loaded. Ensure /static/js/cards.js is included before config.js.');
}


function parseNumericCard(value) {
    if (!/^-?\d+(\.\d+)?$/.test(value)) {
        return null;
    }
    return Number(value);
}

function cardSortComparator(a, b) {
    const aNum = parseNumericCard(a.value);
    const bNum = parseNumericCard(b.value);

    if (aNum !== null && bNum !== null) {
        return aNum - bNum;
    }
    if (aNum !== null) {
        return -1;
    }
    if (bNum !== null) {
        return 1;
    }

    const aSpecial = SPECIAL_CARD_ORDER[a.value] || 99;
    const bSpecial = SPECIAL_CARD_ORDER[b.value] || 99;
    if (aSpecial !== bSpecial) {
        return aSpecial - bSpecial;
    }

    return a.value.localeCompare(b.value);
}

function createCard(value) {
    return { id: String(nextCardID++), value: value.toString() };
}

function getCardsForScale(scale) {
    return (SCALE_PRESETS[scale] || SCALE_PRESETS.fibonacci).map(createCard);
}

function captureCardPositions() {
    const positions = new Map();
    previewCards.querySelectorAll('.preview-card').forEach((el) => {
        positions.set(el.dataset.cardId, el.getBoundingClientRect());
    });
    return positions;
}

function animateReflow(previousPositions) {
    previewCards.querySelectorAll('.preview-card').forEach((el) => {
        const previousRect = previousPositions.get(el.dataset.cardId);
        if (!previousRect) {
            return;
        }

        const nextRect = el.getBoundingClientRect();
        const deltaX = previousRect.left - nextRect.left;
        const deltaY = previousRect.top - nextRect.top;
        if (!deltaX && !deltaY) {
            return;
        }

        el.style.transform = `translate(${deltaX}px, ${deltaY}px)`;
        requestAnimationFrame(() => {
            el.style.transform = 'translate(0, 0)';
        });
    });
}

function removeCard(cardID) {
    const cardEl = previewCards.querySelector(`[data-card-id="${cardID}"]`);
    if (!cardEl) {
        return;
    }

    cardEl.classList.add('is-removing');
    cardEl.addEventListener('animationend', () => {
        const previousPositions = captureCardPositions();
        currentCards = currentCards.filter((card) => card.id !== cardID);
        renderCards(previousPositions);
    }, { once: true });
}

function syncCardsFromDOM() {
    const order = Array.from(previewCards.querySelectorAll('.preview-card')).map((el) => el.dataset.cardId);
    const map = new Map(currentCards.map((card) => [card.id, card]));
    currentCards = order.map((id) => map.get(id)).filter(Boolean);
}

function moveDraggedCardNearCursor(clientX, clientY) {
    const cards = Array.from(previewCards.querySelectorAll('.preview-card:not(.dragging)'));
    const target = cards.find((cardEl) => {
        const rect = cardEl.getBoundingClientRect();
        return clientX < rect.left + rect.width / 2 && clientY < rect.bottom;
    });

    const previousPositions = captureCardPositions();
    if (!target) {
        previewCards.appendChild(draggedElement);
    } else {
        previewCards.insertBefore(draggedElement, target);
    }

    syncCardsFromDOM();
    animateReflow(previousPositions);
}

function buildCardElement(card) {
    const cardEl = document.createElement('div');
    cardEl.className = 'preview-card';
    cardEl.dataset.cardId = card.id;
    cardEl.draggable = true;
    window.CardUI.appendFace(cardEl, card.value);

    const removeBtn = document.createElement('button');
    removeBtn.type = 'button';
    removeBtn.className = 'preview-card-remove';
    removeBtn.textContent = 'X';
    removeBtn.setAttribute('aria-label', `Remove ${card.value}`);
    removeBtn.addEventListener('click', (event) => {
        event.stopPropagation();
        removeCard(card.id);
    });

    cardEl.addEventListener('dragstart', () => {
        draggingCardID = card.id;
        draggedElement = cardEl;
        cardEl.classList.add('dragging', 'wiggle');
    });

    cardEl.addEventListener('dragend', () => {
        draggingCardID = '';
        draggedElement = null;
        cardEl.classList.remove('dragging', 'wiggle');
    });

    cardEl.appendChild(removeBtn);
    return cardEl;
}

function renderCards(previousPositions = new Map()) {
    previewCards.innerHTML = '';
    currentCards.forEach((card) => {
        previewCards.appendChild(buildCardElement(card));
    });

    animateReflow(previousPositions);
}

function setDeck(values, message) {
    const previousPositions = captureCardPositions();
    currentCards = values.map((value) => createCard(value));
    renderCards(previousPositions);
    if (message) {
        statusLine.textContent = message;
    }
}

function resetCardsForScale() {
    const values = (SCALE_PRESETS[scaleSelect.value] || SCALE_PRESETS.fibonacci).slice();
    setDeck(values);
}

function updatePreviewMeta() {
    previewScale.textContent = `Scale: ${scaleSelect.value}`;
    previewMaxPeople.textContent = `Max: ${maxPeopleInput.value || 0}`;
}

function encodeDeckBase64(values) {
    const json = JSON.stringify(values);
    const bytes = new TextEncoder().encode(json);
    let binary = '';
    bytes.forEach((byte) => {
        binary += String.fromCharCode(byte);
    });
    return btoa(binary);
}

function decodeDeckBase64(input) {
    const binary = atob(input.trim());
    const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
    const json = new TextDecoder().decode(bytes);
    const parsed = JSON.parse(json);
    if (!Array.isArray(parsed)) {
        throw new Error('Invalid payload');
    }
    const clean = parsed
        .map((value) => value.toString().trim().slice(0, 8))
        .filter((value) => value !== '');
    if (clean.length === 0) {
        throw new Error('No valid cards');
    }
    return clean;
}

function loadPresets() {
    try {
        const raw = localStorage.getItem(PRESETS_KEY);
        if (!raw) {
            return [];
        }
        const parsed = JSON.parse(raw);
        if (!Array.isArray(parsed)) {
            return [];
        }

        return parsed
            .filter((item) => item && typeof item.name === 'string' && Array.isArray(item.cards))
            .map((item) => ({
                name: item.name.slice(0, 40),
                cards: item.cards.map((card) => card.toString().slice(0, 8)).filter(Boolean),
            }))
            .filter((item) => item.cards.length > 0);
    } catch (_err) {
        return [];
    }
}

function persistPresets() {
    localStorage.setItem(PRESETS_KEY, JSON.stringify(deckPresets));
}

function applyPreset(cards, sourceLabel) {
    setDeck(cards, `${sourceLabel} preset applied.`);
}

function renderPresetList() {
    presetList.innerHTML = '';

    if (deckPresets.length === 0) {
        const empty = document.createElement('div');
        empty.className = 'preset-item';
        empty.textContent = 'No presets saved yet.';
        presetList.appendChild(empty);
        return;
    }

    deckPresets.forEach((preset, index) => {
        const wrapper = document.createElement('div');
        wrapper.className = 'preset-item';

        const left = document.createElement('div');
        const title = document.createElement('div');
        title.textContent = preset.name;
        const meta = document.createElement('div');
        meta.className = 'preset-meta';
        meta.textContent = preset.cards.join(', ');
        left.appendChild(title);
        left.appendChild(meta);

        const actions = document.createElement('div');
        actions.className = 'preset-actions';

        const useBtn = document.createElement('button');
        useBtn.type = 'button';
        useBtn.className = 'btn';
        useBtn.textContent = 'Use';
        useBtn.addEventListener('click', () => {
            applyPreset(preset.cards, preset.name);
            hidePresetPicker();
        });

        const deleteBtn = document.createElement('button');
        deleteBtn.type = 'button';
        deleteBtn.className = 'btn';
        deleteBtn.textContent = 'Del';
        deleteBtn.addEventListener('click', () => {
            deckPresets.splice(index, 1);
            persistPresets();
            renderPresetList();
            statusLine.textContent = 'Preset deleted.';
        });

        actions.appendChild(useBtn);
        actions.appendChild(deleteBtn);

        wrapper.appendChild(left);
        wrapper.appendChild(actions);
        presetList.appendChild(wrapper);
    });
}

function showPresetPicker() {
    presetModalOverlay.classList.remove('hidden');
    pickerToggleButton.setAttribute('aria-expanded', 'true');
    renderPresetList();
}

function hidePresetPicker() {
    presetModalOverlay.classList.add('hidden');
    pickerToggleButton.setAttribute('aria-expanded', 'false');
}

previewCards.addEventListener('dragover', (event) => {
    if (!draggingCardID || !draggedElement) {
        return;
    }
    event.preventDefault();
    moveDraggedCardNearCursor(event.clientX, event.clientY);
});

addCardButton.addEventListener('click', () => {
    const value = customCardInput.value.trim();
    if (!value) {
        return;
    }

    const previousPositions = captureCardPositions();
    currentCards.push(createCard(value.slice(0, 8)));
    renderCards(previousPositions);
    customCardInput.value = '';
    customCardInput.focus();
});

autoSortButton.addEventListener('click', () => {
    const previousPositions = captureCardPositions();
    currentCards = [...currentCards].sort(cardSortComparator);
    renderCards(previousPositions);
    statusLine.textContent = 'Deck auto-sorted.';
});

savePresetButton.addEventListener('click', () => {
    const cards = currentCards.map((card) => card.value);
    if (cards.length === 0) {
        statusLine.textContent = 'Cannot save an empty deck.';
        return;
    }

    const defaultName = `Preset ${deckPresets.length + 1}`;
    const name = window.prompt('Preset name:', defaultName);
    if (!name) {
        return;
    }

    const cleanName = name.trim().slice(0, 40);
    if (!cleanName) {
        statusLine.textContent = 'Preset name is required.';
        return;
    }

    const existingIndex = deckPresets.findIndex((preset) => preset.name === cleanName);
    const newPreset = { name: cleanName, cards };

    if (existingIndex >= 0) {
        deckPresets[existingIndex] = newPreset;
    } else {
        deckPresets.unshift(newPreset);
    }

    deckPresets = deckPresets.slice(0, 20);
    persistPresets();
    renderPresetList();
    statusLine.textContent = `Preset "${cleanName}" saved.`;
});

pickerToggleButton.addEventListener('click', () => {
    if (presetModalOverlay.classList.contains('hidden')) {
        showPresetPicker();
        return;
    }
    hidePresetPicker();
});

shareDeckButton.addEventListener('click', async () => {
    const cards = currentCards.map((card) => card.value);
    if (cards.length === 0) {
        statusLine.textContent = 'Cannot share an empty deck.';
        return;
    }

    const encoded = encodeDeckBase64(cards);

    try {
        await navigator.clipboard.writeText(encoded);
        statusLine.textContent = 'Shared deck copied as base64.';
    } catch (_err) {
        window.prompt('Copy this base64 deck string:', encoded);
        statusLine.textContent = 'Clipboard unavailable. Base64 shown for manual copy.';
    }
});

importToggleButton.addEventListener('click', () => {
    importPane.classList.toggle('hidden');
    if (!importPane.classList.contains('hidden')) {
        importInput.focus();
    }
});

importApplyButton.addEventListener('click', () => {
    const raw = importInput.value.trim();
    if (!raw) {
        statusLine.textContent = 'Paste a base64 deck first.';
        return;
    }

    try {
        const decodedCards = decodeDeckBase64(raw);
        applyPreset(decodedCards, 'Imported');
        importInput.value = '';
        importPane.classList.add('hidden');
        hidePresetPicker();
    } catch (_err) {
        statusLine.textContent = 'Invalid base64 deck input.';
    }
});

presetModalOverlay.addEventListener('click', (event) => {
    if (event.target === presetModalOverlay) {
        hidePresetPicker();
    }
});

presetModalCloseButton.addEventListener('click', hidePresetPicker);
presetModalDoneButton.addEventListener('click', hidePresetPicker);

customCardInput.addEventListener('keydown', (event) => {
    if (event.key === 'Enter') {
        event.preventDefault();
        addCardButton.click();
    }
});

scaleSelect.addEventListener('change', () => {
    resetCardsForScale();
    updatePreviewMeta();
    statusLine.textContent = 'Card deck reset to selected estimation scale.';
});

maxPeopleInput.addEventListener('input', updatePreviewMeta);

roomConfigForm.addEventListener('submit', async (event) => {
    event.preventDefault();

    const formData = new FormData(roomConfigForm);
    const username = (formData.get('username') || '').toString().trim();
    const roomName = (formData.get('roomName') || '').toString().trim();

    if (!username || !roomName) {
        statusLine.textContent = 'Room name and username are required.';
        return;
    }

    localStorage.setItem(USERNAME_KEY, username);

    const payload = {
        roomName,
        creatorUsername: username,
        maxPeople: Number(formData.get('maxPeople') || 50),
        cards: currentCards.map((card) => card.value),
        allowSpectators: Boolean(formData.get('allowSpectators')),
        anonymousVoting: Boolean(formData.get('anonymousVoting')),
        autoReset: Boolean(formData.get('autoReset')),
        revealMode: (formData.get('revealMode') || 'manual').toString(),
        votingTimeoutSec: Number(formData.get('votingTimeoutSec') || 0),
        password: (formData.get('password') || '').toString(),
    };

    statusLine.textContent = 'Creating room...';

    try {
        const response = await fetch('/api/rooms', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(payload),
        });

        const data = await response.json();
        if (!response.ok) {
            statusLine.textContent = data.error || 'Failed to create room.';
            return;
        }

        const target = `/room/${encodeURIComponent(data.roomId)}?participantId=${encodeURIComponent(data.creatorParticipantId)}&adminToken=${encodeURIComponent(data.adminToken)}&username=${encodeURIComponent(payload.creatorUsername)}`;
        window.location.assign(target);
    } catch (_err) {
        statusLine.textContent = 'Network error while creating room.';
    }
});

roomConfigForm.addEventListener('reset', () => {
    window.setTimeout(() => {
        updatePreviewMeta();
        resetCardsForScale();
        statusLine.textContent = 'Room settings reset to defaults.';
    }, 0);
});

updatePreviewMeta();
resetCardsForScale();
renderPresetList();
