import { apiGet, apiPost, apiPut, apiDelete } from '../api.js';
import { getRole, getUser, pageHeaderHTML, showToast } from '../app.js';
import { confirmAction } from '../confirm-modal.js';
import { openAdminResetPasswordModal } from '../password-modal.js';
import { berlinDateInputValue, formatBerlinDateTimeShort } from '../datetime.js';

// Roles an admin can create; supervisors can only create coaches
const CREATEABLE_ROLES = {
    admin:      ['admin', 'supervisor', 'coach'],
    supervisor: ['coach'],
};

let usersList       = [];
let supervisorsList = [];
let callerRole      = '';
/** @type {Record<string, string>} */
let filterSearchByRole = { admin: '', supervisor: '', coach: '' };

function roleGroupsForCaller() {
    return callerRole === 'supervisor'
        ? [{ label: 'Counselor', key: 'coach' }]
        : [
            { label: 'Admins', key: 'admin' },
            { label: 'Supervisors', key: 'supervisor' },
            { label: 'Counselor', key: 'coach' },
        ];
}

function searchPlaceholderForRole(roleKey) {
    return roleKey === 'coach'
        ? 'Search username or supervisor…'
        : 'Search username or location…';
}

function usersByRoleMap() {
    const byRole = { admin: [], supervisor: [], coach: [] };
    usersList.forEach(u => {
        if (byRole[u.role]) byRole[u.role].push(u);
        else (byRole.other = byRole.other || []).push(u);
    });
    return byRole;
}

export async function usersPage() {
    callerRole = getRole();
    const app = document.getElementById('app');

    app.innerHTML = `
        ${pageHeaderHTML('Users', `
                <button class="btn" id="downloadUsersBtn" ${usersList.length ? '' : 'disabled'}>Download CSV</button>
                <button class="btn btn-primary" id="showCreateFormBtn">+ Create User</button>
        `)}
        <div id="createUserWrapper" style="display:none"></div>
        <div id="usersContent"><div class="spinner"></div></div>
    `;

    document.getElementById('showCreateFormBtn').addEventListener('click', () => {
        const wrapper = document.getElementById('createUserWrapper');
        if (wrapper.style.display === 'none') {
            showCreateForm();
        } else {
            hideCreateForm();
        }
    });
    document.getElementById('downloadUsersBtn').addEventListener('click', downloadUsersCSV);

    await loadUsers();
}

document.addEventListener('qdb:password-reset', (e) => {
    const { userID, mustChangePassword } = e.detail || {};
    const u = usersList.find(x => x.userID === userID);
    if (u) {
        u.mustChangePassword = mustChangePassword;
        renderUsers();
    }
});

async function loadUsers() {
    try {
        const data = await apiGet('users.php');
        usersList       = data.users       || [];
        supervisorsList = data.supervisors || [];
        callerRole      = data.callerRole  || callerRole;
        renderUsers();
        const dlBtn = document.getElementById('downloadUsersBtn');
        if (dlBtn) dlBtn.disabled = !usersList.length;
    } catch (e) {
        showToast(e.message, 'error');
        document.getElementById('usersContent').innerHTML =
            `<p class="error-text" style="padding:16px">${esc(e.message)}</p>`;
    }
}

// ── User table ────────────────────────────────────────────────────────────

function renderUsers() {
    const container = document.getElementById('usersContent');
    const myUsername = getUser();

    if (!usersList.length) {
        container.innerHTML = `
            <div class="card">
                <div class="empty-state">
                    <h3>No users found</h3>
                    <p>${callerRole === 'supervisor' ? 'You have no counselors yet.' : 'Create the first user above.'}</p>
                </div>
            </div>`;
        return;
    }

    const byRole = usersByRoleMap();
    const groups = roleGroupsForCaller();

    container.innerHTML = groups.map(group => {
        const allInRole = byRole[group.key] || [];
        if (!allInRole.length) return '';
        return `
        <div class="card user-role-card" data-role="${group.key}" style="margin-bottom:16px">
            <h3 class="user-role-title" style="margin-bottom:12px">
                ${group.label} (<span data-role-count="${group.key}">0</span>)
            </h3>
            <div class="filter-bar">
                <input type="search" class="filter-search user-role-search" data-role="${group.key}"
                    placeholder="${searchPlaceholderForRole(group.key)}"
                    value="${esc(filterSearchByRole[group.key] || '')}">
            </div>
            <div class="table-wrapper">
                <table class="data-table">
                    <thead>
                        <tr>
                            <th>Username</th>
                            ${group.key !== 'coach' ? '<th>Location</th>' : '<th>Supervisor</th>'}
                            <th>Must change password</th>
                            <th>Created</th>
                            <th>Actions</th>
                        </tr>
                    </thead>
                    <tbody id="usersBody-${group.key}"></tbody>
                </table>
            </div>
        </div>`;
    }).join('');

    container.addEventListener('input', (e) => {
        const input = e.target.closest('.user-role-search');
        if (!input) return;
        const roleKey = input.dataset.role;
        if (!roleKey) return;
        filterSearchByRole[roleKey] = input.value;
        updateRoleGroupTable(roleKey, myUsername);
    });

    groups.forEach(group => {
        if ((byRole[group.key] || []).length) {
            updateRoleGroupTable(group.key, myUsername);
        }
    });
}

function filterUsers(users, roleKey) {
    let list = users;
    const q = (filterSearchByRole[roleKey] || '').trim().toLowerCase();
    if (q) {
        list = list.filter(u => {
            const hay = [u.username, u.location, u.supervisorUsername].filter(Boolean).join(' ').toLowerCase();
            return hay.includes(q);
        });
    }
    return list;
}

function updateRoleGroupTable(roleKey, myUsername) {
    const tbody = document.getElementById(`usersBody-${roleKey}`);
    const countEl = document.querySelector(`[data-role-count="${roleKey}"]`);
    if (!tbody) return;

    const byRole = usersByRoleMap();
    const allInRole = byRole[roleKey] || [];
    const users = filterUsers(allInRole, roleKey);
    const colSpan = 5;

    if (countEl) {
        const q = (filterSearchByRole[roleKey] || '').trim();
        countEl.textContent = q && users.length !== allInRole.length
            ? `${users.length} of ${allInRole.length}`
            : String(users.length);
    }

    if (!users.length) {
        tbody.innerHTML = `
            <tr>
                <td colspan="${colSpan}" style="text-align:center;color:var(--text-secondary);padding:24px">
                    ${allInRole.length ? 'No users match' : 'No users'}
                </td>
            </tr>`;
        return;
    }

    tbody.innerHTML = users.map(u => userRowHTML(u, myUsername)).join('');
    tbody.querySelectorAll('.delete-user-btn').forEach(btn => {
        btn.addEventListener('click', () => deleteUser(btn.dataset.id, btn.dataset.name));
    });
    tbody.querySelectorAll('.reset-password-btn').forEach(btn => {
        btn.addEventListener('click', () => openAdminResetPasswordModal({
            userID: btn.dataset.id,
            username: btn.dataset.name,
            role: btn.dataset.role || '',
        }));
    });
    tbody.querySelectorAll('.revoke-sessions-btn').forEach(btn => {
        btn.addEventListener('click', () => revokeUserSessions(btn.dataset.id, btn.dataset.name));
    });
    tbody.querySelectorAll('.coach-supervisor-select').forEach(sel => {
        sel.addEventListener('change', () => reassignCoachSupervisor(sel));
    });
}

function supervisorSelectHTML(u) {
    if (!supervisorsList.length) {
        return '<span class="data-toolbar-hint">No supervisors</span>';
    }
    const cur = u.supervisorID || '';
    const opts = supervisorsList.map(s => {
        const label = s.location ? `${s.username} (${s.location})` : s.username;
        const selected = s.supervisorID === cur ? ' selected' : '';
        return `<option value="${esc(s.supervisorID)}"${selected}>${esc(label)}</option>`;
    }).join('');
    return `<select class="coach-supervisor-select" data-user-id="${esc(u.userID)}"
        data-username="${esc(u.username)}" data-prev="${esc(cur)}" aria-label="Supervisor for ${esc(u.username)}">
        ${opts}
    </select>`;
}

function userRowHTML(u, myUsername) {
    const isSelf   = u.username === myUsername;
    let detail;
    if (u.role === 'coach') {
        detail = callerRole === 'admin'
            ? supervisorSelectHTML(u)
            : esc(u.supervisorUsername || '—');
    } else {
        detail = esc(u.location || '—');
    }
    const created  = u.createdAt
        ? new Date(parseInt(u.createdAt, 10) * 1000).toLocaleDateString()
        : '—';
    const pwBadge  = u.mustChangePassword == 1
        ? '<span class="badge badge-pending" title="Must choose a new password on next sign-in">Temporary</span>'
        : '';

    const canDelete = !isSelf && (
        callerRole === 'admin' ||
        (callerRole === 'supervisor' && u.role === 'coach')
    );
    const canResetPassword = !isSelf && (
        (callerRole === 'admin' && (u.role === 'supervisor' || u.role === 'coach')) ||
        (callerRole === 'supervisor' && u.role === 'coach')
    );
    const canRevokeSessions = !isSelf && (
        callerRole === 'admin' ||
        (callerRole === 'supervisor' && u.role === 'coach')
    );

    const actions = [];
    if (canResetPassword) {
        actions.push(
            `<button type="button" class="btn btn-sm reset-password-btn" data-id="${u.userID}" data-name="${esc(u.username)}" data-role="${esc(u.role)}">Reset password</button>`
        );
    }
    if (canRevokeSessions) {
        actions.push(
            `<button type="button" class="btn btn-sm revoke-sessions-btn" data-id="${u.userID}" data-name="${esc(u.username)}">Sign out everywhere</button>`
        );
    }
    if (canDelete) {
        actions.push(
            `<button type="button" class="btn btn-sm btn-danger delete-user-btn" data-id="${u.userID}" data-name="${esc(u.username)}">Delete</button>`
        );
    }

    return `
        <tr>
            <td>
                <strong>${esc(u.username)}</strong>
                ${isSelf ? '<span class="badge badge-you">You</span>' : ''}
            </td>
            <td>${detail}</td>
            <td>${pwBadge}</td>
            <td>${created}</td>
            <td class="user-actions-cell">${actions.join(' ')}</td>
        </tr>`;
}

async function reassignCoachSupervisor(selectEl) {
    const userID = selectEl.dataset.userId;
    const username = selectEl.dataset.username || '';
    const prev = selectEl.dataset.prev || '';
    const supervisorID = selectEl.value;

    if (supervisorID === prev) {
        return;
    }

    selectEl.disabled = true;
    try {
        const data = await apiPut('users.php', { userID, supervisorID });
        const u = usersList.find(x => x.userID === userID);
        if (u) {
            u.supervisorID = data.supervisorID ?? supervisorID;
            u.supervisorUsername = data.supervisorUsername ?? '';
        }
        selectEl.dataset.prev = supervisorID;
        showToast(`Counselor "${username}" assigned to ${data.supervisorUsername || 'supervisor'}`, 'success');
    } catch (e) {
        selectEl.value = prev;
        showToast(e.message, 'error');
    } finally {
        selectEl.disabled = false;
    }
}

async function revokeUserSessions(userID, username) {
    if (!(await confirmAction({
        title: 'Sign out everywhere',
        message: `Sign out "${username}" on all devices?\n\nThey must log in again on the website and mobile app.`,
        confirmLabel: 'Sign out',
        variant: 'danger',
    }))) {
        return;
    }
    try {
        const data = await apiPut('users.php', { action: 'revokeSessions', userID });
        if (!data.success) throw new Error(data.error || 'Failed');
        const n = data.revokedSessions ?? 0;
        showToast(`Signed out "${username}" (${n} session${n === 1 ? '' : 's'} revoked)`, 'success');
    } catch (e) {
        showToast(e.message, 'error');
    }
}

async function deleteUser(userID, username) {
    if (!(await confirmAction({
        title: 'Delete user',
        message: `Delete user "${username}"? This cannot be undone.`,
        confirmLabel: 'Delete',
        variant: 'danger',
    }))) return;
    try {
        const data = await apiDelete('users.php', { userID });
        if (data.success) {
            usersList = usersList.filter(u => u.userID !== userID);
            showToast(`User "${username}" deleted`, 'success');
            renderUsers();
        }
    } catch (e) {
        showToast(e.message, 'error');
    }
}

// ── Create user form ──────────────────────────────────────────────────────

function showCreateForm() {
    const wrapper = document.getElementById('createUserWrapper');
    const allowedRoles = CREATEABLE_ROLES[callerRole] || ['coach'];
    const isSupervisor = callerRole === 'supervisor';

    wrapper.style.display = '';
    wrapper.innerHTML = `
        <div class="inline-form-card" style="margin-bottom:20px">
            <h4>Create New User</h4>
            <div class="form-row">
                <div class="form-group" style="flex:2">
                    <label>Username</label>
                    <input type="text" id="cu_username" autocomplete="off" placeholder="Enter username">
                </div>
                <div class="form-group" style="flex:2">
                    <label>Password</label>
                    <input type="password" id="cu_password" autocomplete="new-password" placeholder="Min 6 characters">
                </div>
                <div class="form-group" style="flex:1;min-width:160px">
                    <label>Role</label>
                    ${isSupervisor
                        ? `<input type="text" value="Counselor" disabled>`
                        : `<select id="cu_role">
                            ${allowedRoles.map(r =>
                                `<option value="${r}">${r === 'coach' ? 'Counselor' : r.charAt(0).toUpperCase() + r.slice(1)}</option>`
                            ).join('')}
                           </select>`
                    }
                </div>
            </div>

            <div id="cu_location_row" class="form-group" ${isSupervisor ? 'style="display:none"' : ''}>
                <label>Location <span style="font-weight:400;color:var(--text-secondary)">(for admin/supervisor)</span></label>
                <input type="text" id="cu_location" placeholder="e.g. Stuttgart">
            </div>

            <div id="cu_supervisor_row" class="form-group" style="${isSupervisor ? '' : 'display:none'}">
                <label>Supervisor</label>
                ${isSupervisor
                    ? `<input type="text" value="You (auto-assigned)" disabled>`
                    : `<select id="cu_supervisor_select">
                        <option value="">— select supervisor —</option>
                        ${supervisorsList.map(s =>
                            `<option value="${s.supervisorID}">${esc(s.username)}${s.location ? ` (${esc(s.location)})` : ''}</option>`
                        ).join('')}
                       </select>`
                }
            </div>

            <p class="modal-hint" style="margin-bottom:14px">
                They must choose their own password on first sign-in.
            </p>

            <div style="display:flex;gap:8px">
                <button class="btn btn-primary btn-sm" id="cu_submit">Create User</button>
                <button class="btn btn-sm" id="cu_cancel">Cancel</button>
            </div>
            <p id="cu_error" class="error-text" style="display:none;margin-top:8px"></p>
        </div>
    `;

    document.getElementById('cu_username').focus();

    // Show/hide location vs supervisor field based on role selection (admin only)
    if (!isSupervisor) {
        document.getElementById('cu_role').addEventListener('change', (e) => {
            const r = e.target.value;
            document.getElementById('cu_location_row').style.display   = r !== 'coach' ? '' : 'none';
            document.getElementById('cu_supervisor_row').style.display = r === 'coach' ? '' : 'none';
        });
        // Set initial state based on default selection
        const initRole = document.getElementById('cu_role').value;
        document.getElementById('cu_location_row').style.display   = initRole !== 'coach' ? '' : 'none';
        document.getElementById('cu_supervisor_row').style.display = initRole === 'coach' ? '' : 'none';
    }

    document.getElementById('cu_submit').addEventListener('click', submitCreateUser);
    document.getElementById('cu_cancel').addEventListener('click', hideCreateForm);

    // Enter key on last visible field submits
    wrapper.querySelectorAll('input').forEach(inp => {
        inp.addEventListener('keydown', (e) => {
            if (e.key === 'Enter') submitCreateUser();
            if (e.key === 'Escape') hideCreateForm();
        });
    });
}

function hideCreateForm() {
    const wrapper = document.getElementById('createUserWrapper');
    if (wrapper) { wrapper.style.display = 'none'; wrapper.innerHTML = ''; }
}

async function submitCreateUser() {
    const errEl = document.getElementById('cu_error');
    errEl.style.display = 'none';

    const isSupervisor = callerRole === 'supervisor';
    const username     = document.getElementById('cu_username').value.trim();
    const password     = document.getElementById('cu_password').value;
    const role         = isSupervisor ? 'coach' : (document.getElementById('cu_role').value || 'coach');
    const mustChange   = 1;

    let location     = '';
    let supervisorID = '';
    if (!isSupervisor) {
        if (role !== 'coach') {
            location = document.getElementById('cu_location').value.trim();
        } else {
            supervisorID = document.getElementById('cu_supervisor_select').value;
        }
    }

    if (!username) { showError(errEl, 'Username is required'); return; }
    if (password.length < 6) { showError(errEl, 'Password must be at least 6 characters'); return; }
    if (role === 'coach' && !isSupervisor && !supervisorID) {
        showError(errEl, 'Please select a supervisor for this counselor');
        return;
    }

    const btn = document.getElementById('cu_submit');
    btn.disabled = true;
    btn.textContent = 'Creating...';

    try {
        const data = await apiPost('users.php', {
            username, password, role, location, supervisorID, mustChangePassword: mustChange,
        });
        if (!data.success) throw new Error(data.error || 'Failed to create user');

        // Add to local list and re-render
        usersList.push({
            userID:             data.userID,
            username:           data.username,
            role:               data.role,
            entityID:           data.entityID,
            location:           data.location || '',
            supervisorID:       data.supervisorID || null,
            supervisorUsername: data.supervisorUsername || null,
            mustChangePassword: data.mustChangePassword,
            createdAt:          data.createdAt,
        });
        showToast(`User "${data.username}" created`, 'success');
        hideCreateForm();
        renderUsers();
    } catch (e) {
        showError(errEl, e.message);
        btn.disabled = false;
        btn.textContent = 'Create User';
    }
}

function showError(el, msg) {
    el.textContent = msg;
    el.style.display = '';
}

function downloadUsersCSV() {
    if (!usersList.length) {
        showToast('No users to export', 'error');
        return;
    }

    const headers = ['username', 'role', 'location', 'supervisor', 'mustChangePassword', 'createdAt', 'userID'];
    const rows = usersList.map(u => [
        u.username,
        u.role === 'coach' ? 'Counselor' : u.role,
        u.role === 'coach' ? '' : (u.location || ''),
        u.role === 'coach' ? (u.supervisorUsername || u.supervisorID || '') : '',
        u.mustChangePassword == 1 ? 'yes' : 'no',
        u.createdAt ? formatBerlinDateTimeShort(parseInt(u.createdAt, 10) * 1000) : '',
        u.userID,
    ]);

    let csv = '\uFEFF';
    csv += headers.map(csvEsc).join(',') + '\n';
    rows.forEach(r => { csv += r.map(csvEsc).join(',') + '\n'; });

    const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `users_${berlinDateInputValue()}.csv`;
    a.click();
    URL.revokeObjectURL(url);
    showToast('Users exported', 'success');
}

function csvEsc(val) {
    const s = String(val ?? '');
    if (s.includes(',') || s.includes('"') || s.includes('\n')) {
        return '"' + s.replace(/"/g, '""') + '"';
    }
    return s;
}

function esc(s) {
    const d = document.createElement('div');
    d.textContent = s ?? '';
    return d.innerHTML;
}
