<?php
$pageTitle = Helper::e($project['name']) . ' – ' . t('list');

/**
 * Build the URL for clicking a column header. Preserves the current filter
 * state (status / priority / assignee / search), keeps the list view active,
 * and toggles asc ↔ desc when the user clicks the column that is already
 * the active sort.
 */
$listSortUrl = function (string $key) use ($project, $sortKey, $sortDir, $filterStatus, $filterPriority, $filterAssignee, $search): string {
    $params = ['view' => 'list'];
    if ($filterStatus)   $params['status_id']   = $filterStatus;
    if ($filterPriority) $params['priority']    = $filterPriority;
    if ($filterAssignee) $params['assigned_to'] = $filterAssignee;
    if ($search !== '')  $params['search']      = $search;
    $params['sort'] = $key;
    $params['dir']  = ($sortKey === $key && $sortDir === 'asc') ? 'desc' : 'asc';
    return '/project/' . (int)$project['id'] . '?' . http_build_query($params);
};
?>

<div class="project-header">
    <div class="project-header-left">
        <a href="/projects" class="btn btn-ghost btn-sm">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>
            <?= t('projects') ?>
        </a>
        <span class="project-dot" style="background:<?= Helper::e($project['color']) ?>"></span>
        <h1 class="page-title"><?= Helper::e($project['name']) ?></h1>
    </div>
    <div class="project-header-actions">
        <?php if (in_array($myRole, ['owner','manager','member'])): ?>
        <a href="/task/create/<?= $project['id'] ?>" class="btn btn-primary btn-sm">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14"><path d="M12 5v14M5 12h14"/></svg>
            <?= t('new_task') ?>
        </a>
        <?php endif; ?>
        <?php if (in_array($myRole, ['owner','manager'])): ?>
        <a href="/project/<?= $project['id'] ?>/settings" class="btn btn-ghost btn-sm"><?= t('project_settings') ?></a>
        <a href="/project/<?= $project['id'] ?>/members" class="btn btn-ghost btn-sm"><?= t('members') ?></a>
        <?php endif; ?>
    </div>
</div>

<!-- View switcher -->
<div class="view-switcher">
    <a href="/project/<?= $project['id'] ?>?view=kanban" class="view-tab">Kanban</a>
    <a href="/project/<?= $project['id'] ?>?view=list" class="view-tab active"><?= t('list') ?></a>
    <a href="/project/<?= $project['id'] ?>?view=gantt" class="view-tab">Gantt</a>
    <?php if (AI::isEnabled() && !Auth::isAiBlockedForUser() && in_array($myRole, ['owner','manager','member'])): ?>
    <a href="/project/<?= $project['id'] ?>/ai" class="view-tab view-tab--ai">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14"><path d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/></svg>
        <?= t('ai_assistant') ?>
    </a>
    <?php endif; ?>
</div>

<!-- Filters -->
<form method="GET" action="/project/<?= $project['id'] ?>" class="filter-bar">
    <input type="hidden" name="view" value="list">
    <input type="text" name="search" class="form-input filter-search"
           placeholder="<?= t('search') ?>..." value="<?= Helper::e($search) ?>">
    <select name="status_id" class="form-select filter-select">
        <option value=""><?= t('task_status') ?>: <?= t('all') ?></option>
        <?php foreach ($statuses as $s): ?>
        <option value="<?= $s['id'] ?>" <?= $filterStatus == $s['id'] ? 'selected' : '' ?>><?= Helper::e($s['name']) ?></option>
        <?php endforeach; ?>
    </select>
    <select name="priority" class="form-select filter-select">
        <option value=""><?= t('priority') ?>: <?= t('all') ?></option>
        <?php foreach (['low','medium','high','urgent'] as $p): ?>
        <option value="<?= $p ?>" <?= $filterPriority === $p ? 'selected' : '' ?>><?= t('priority_' . $p) ?></option>
        <?php endforeach; ?>
    </select>
    <select name="assigned_to" class="form-select filter-select">
        <option value=""><?= t('assigned_to') ?>: <?= t('all') ?></option>
        <?php foreach ($members as $m): ?>
        <option value="u_<?= $m['user_id'] ?>" <?= $filterAssignee === 'u_' . $m['user_id'] ? 'selected' : '' ?>><?= Helper::e($m['username']) ?></option>
        <?php endforeach; ?>
        <?php if (!empty($externals)): ?>
        <optgroup label="<?= t('external_participants') ?>">
        <?php foreach ($externals as $e): ?>
        <option value="e_<?= $e['id'] ?>" <?= $filterAssignee === 'e_' . $e['id'] ? 'selected' : '' ?>><?= Helper::e($e['name']) ?></option>
        <?php endforeach; ?>
        </optgroup>
        <?php endif; ?>
        <?php if (!empty($dummies)): ?>
        <optgroup label="<?= t('dummy_assignees') ?>">
        <?php foreach ($dummies as $d): ?>
        <option value="e_<?= $d['id'] ?>" <?= $filterAssignee === 'e_' . $d['id'] ? 'selected' : '' ?>><?= Helper::e($d['name']) ?></option>
        <?php endforeach; ?>
        </optgroup>
        <?php endif; ?>
    </select>
    <button type="submit" class="btn btn-ghost btn-sm"><?= t('filter') ?></button>
    <?php if ($filterStatus || $filterPriority || $filterAssignee || $search): ?>
    <a href="/project/<?= $project['id'] ?>?view=list" class="btn btn-ghost btn-sm">✕</a>
    <?php endif; ?>
</form>

<!-- Task table -->
<?php if (empty($tasks)): ?>
<div class="empty-state">
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" width="64" height="64" opacity=".3"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 01-2 2H5a2 2 0 01-2-2V5a2 2 0 012-2h11"/></svg>
    <h3><?= t('no_tasks') ?></h3>
    <?php if (in_array($myRole, ['owner','manager','member'])): ?>
    <a href="/task/create/<?= $project['id'] ?>" class="btn btn-primary"><?= t('new_task') ?></a>
    <?php endif; ?>
</div>
<?php else: ?>
<?php $canBulk = in_array($myRole, ['owner','manager','member']); ?>

<?php if ($canBulk): ?>
<!-- Bulk-edit toolbar — appears when ≥1 task is checked -->
<div id="bulkBar" class="bulk-bar" style="display:none">
    <span class="bulk-bar-count"><span id="bulkCount">0</span> <?= t('bulk_selected') ?></span>
    <div class="bulk-bar-actions">
        <div class="bulk-action">
            <button type="button" class="btn btn-ghost btn-xs" data-bulk="status"><?= t('bulk_set_status') ?></button>
            <div class="bulk-menu" data-menu="status">
                <?php foreach ($statuses as $s): ?>
                <button type="button" class="bulk-menu-item" data-value="<?= (int)$s['id'] ?>"><?= Helper::e($s['name']) ?></button>
                <?php endforeach; ?>
            </div>
        </div>
        <div class="bulk-action">
            <button type="button" class="btn btn-ghost btn-xs" data-bulk="priority"><?= t('bulk_set_priority') ?></button>
            <div class="bulk-menu" data-menu="priority">
                <?php foreach (['low','medium','high','urgent'] as $p): ?>
                <button type="button" class="bulk-menu-item" data-value="<?= $p ?>"><?= t('priority_' . $p) ?></button>
                <?php endforeach; ?>
            </div>
        </div>
        <div class="bulk-action">
            <button type="button" class="btn btn-ghost btn-xs" data-bulk="assign"><?= t('bulk_set_assignees') ?></button>
            <div class="bulk-menu bulk-menu--checks" data-menu="assign">
                <div class="bulk-menu-scroll">
                    <?php foreach ($members as $m): ?>
                    <label class="bulk-menu-check"><input type="checkbox" data-uid="<?= (int)$m['user_id'] ?>"> <?= Helper::e($m['username']) ?></label>
                    <?php endforeach; ?>
                    <?php foreach ($externals as $ext): ?>
                    <label class="bulk-menu-check"><input type="checkbox" data-eid="<?= (int)$ext['id'] ?>"> <?= Helper::e($ext['name']) ?> <span class="text-muted">(<?= t('external') ?>)</span></label>
                    <?php endforeach; ?>
                    <?php foreach ($dummies as $d): ?>
                    <label class="bulk-menu-check"><input type="checkbox" data-eid="<?= (int)$d['id'] ?>"> <?= Helper::e($d['name']) ?></label>
                    <?php endforeach; ?>
                </div>
                <button type="button" class="btn btn-primary btn-xs" data-action="bulk-apply-assign"><?= t('bulk_apply') ?></button>
            </div>
        </div>
        <div class="bulk-action">
            <button type="button" class="btn btn-ghost btn-xs" data-bulk="due"><?= t('bulk_set_due_date') ?></button>
            <div class="bulk-menu" data-menu="due">
                <input type="date" class="form-input" id="bulkDueInput">
                <div style="display:flex;gap:6px;margin-top:6px">
                    <button type="button" class="btn btn-primary btn-xs" data-action="bulk-apply-due"><?= t('bulk_apply') ?></button>
                    <button type="button" class="btn btn-ghost btn-xs" data-action="bulk-clear-due"><?= t('clear') ?></button>
                </div>
            </div>
        </div>
        <?php if (!empty($labels)): ?>
        <div class="bulk-action">
            <button type="button" class="btn btn-ghost btn-xs" data-bulk="label_add"><?= t('bulk_add_label') ?></button>
            <div class="bulk-menu" data-menu="label_add">
                <?php foreach ($labels as $l): ?>
                <button type="button" class="bulk-menu-item" data-value="<?= (int)$l['id'] ?>">
                    <span class="label-dot" style="background:<?= Helper::e($l['color']) ?>"></span> <?= Helper::e($l['name']) ?>
                </button>
                <?php endforeach; ?>
            </div>
        </div>
        <div class="bulk-action">
            <button type="button" class="btn btn-ghost btn-xs" data-bulk="label_remove"><?= t('bulk_remove_label') ?></button>
            <div class="bulk-menu" data-menu="label_remove">
                <?php foreach ($labels as $l): ?>
                <button type="button" class="bulk-menu-item" data-value="<?= (int)$l['id'] ?>">
                    <span class="label-dot" style="background:<?= Helper::e($l['color']) ?>"></span> <?= Helper::e($l['name']) ?>
                </button>
                <?php endforeach; ?>
            </div>
        </div>
        <?php endif; ?>
        <button type="button" class="btn btn-ghost btn-xs danger" data-action="bulk-delete"><?= t('bulk_delete') ?></button>
        <button type="button" class="btn btn-ghost btn-xs" data-action="bulk-clear"><?= t('bulk_clear') ?></button>
    </div>
</div>
<?php endif; ?>

<style>
.data-table thead a.sort-link { color: inherit; text-decoration: none; display: inline-flex; align-items: center; gap: 4px; cursor: pointer; }
.data-table thead a.sort-link:hover { color: var(--color-primary); }
.data-table thead a.sort-link--active { color: var(--text-primary); font-weight: 600; }
.data-table thead .sort-arrow { font-size: .7em; line-height: 1; opacity: .85; }
</style>
<div class="table-card">
    <table class="data-table">
        <thead>
            <tr>
                <?php if ($canBulk): ?><th style="width:32px"><input type="checkbox" id="bulkAll"></th><?php endif; ?>
                <?php
                $sortHeader = function (string $key, string $label) use ($listSortUrl, $sortKey, $sortDir) {
                    $active = $sortKey === $key;
                    $arrow  = $active ? ($sortDir === 'asc' ? ' ▲' : ' ▼') : '';
                    $cls    = 'sort-link' . ($active ? ' sort-link--active' : '');
                    echo '<a class="' . $cls . '" href="' . Helper::e($listSortUrl($key)) . '">'
                       . Helper::e($label) . '<span class="sort-arrow">' . $arrow . '</span></a>';
                };
                ?>
                <th><?php $sortHeader('title',    t('task_title')); ?></th>
                <th><?php $sortHeader('status',   t('task_status')); ?></th>
                <th><?php $sortHeader('priority', t('priority')); ?></th>
                <th><?= t('assigned_to') ?></th>
                <th><?php $sortHeader('start',    t('start_date')); ?></th>
                <th><?php $sortHeader('due',      t('due_date')); ?></th>
                <th></th>
            </tr>
        </thead>
        <tbody>
        <?php foreach ($tasks as $task): ?>
        <tr class="table-row-link" data-task-id="<?= (int)$task['id'] ?>" data-href="/task/<?= $task['id'] ?>">
            <?php if ($canBulk): ?>
            <td data-stop-propagation style="text-align:center">
                <input type="checkbox" class="bulk-check" data-tid="<?= (int)$task['id'] ?>" data-stop-propagation>
            </td>
            <?php endif; ?>
            <td>
                <a href="/task/<?= $task['id'] ?>" class="task-link"><?= Helper::e($task['title']) ?></a>
            </td>
            <td>
                <?php if ($task['status_name']): ?>
                <span class="status-badge" style="--status-color:<?= Helper::e($task['status_color']) ?>">
                    <?= Helper::e($task['status_name']) ?>
                </span>
                <?php endif; ?>
            </td>
            <td><?= Helper::priorityBadge($task['priority']) ?></td>
            <td data-stop-propagation>
                <?php $canEditAssignees = in_array($myRole, ['owner','manager','member']); ?>
                <div class="assignee-cell <?= $canEditAssignees ? 'assignee-cell--editable' : '' ?>"
                     data-task-id="<?= (int)$task['id'] ?>">
                    <span class="assignee-cell-chips"><?= Helper::assigneeChips($task['assignees'] ?? [], 18, $canEditAssignees) ?></span>
                    <?php if ($canEditAssignees): ?>
                    <button type="button" class="assignee-add-btn" title="<?= t('bulk_set_assignees') ?>" aria-label="<?= t('bulk_set_assignees') ?>">
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" width="13" height="13"><path d="M12 5v14M5 12h14"/></svg>
                    </button>
                    <?php endif; ?>
                </div>
            </td>
            <td>
                <?php if ($task['start_date']): ?>
                    <?= Helper::formatDate($task['start_date']) ?>
                <?php else: ?>—<?php endif; ?>
            </td>
            <td>
                <?php if ($task['due_date']): ?>
                <span class="task-due <?= $task['due_date'] < date('Y-m-d') ? 'overdue' : ($task['due_date'] === date('Y-m-d') ? 'due-today' : '') ?>">
                    <?= Helper::formatDate($task['due_date']) ?>
                </span>
                <?php else: ?>—<?php endif; ?>
            </td>
            <td>
                <?php if (in_array($myRole, ['owner','manager','member'])): ?>
                <a href="/task/<?= $task['id'] ?>/edit" class="icon-btn-sm" data-stop-propagation>
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
                </a>
                <?php endif; ?>
            </td>
        </tr>
        <?php endforeach; ?>
        </tbody>
    </table>
</div>

<?php if ($canBulk): ?>
<style>
.bulk-bar { position:sticky; top:0; z-index:100; display:flex; align-items:center; justify-content:space-between; gap:12px; padding:8px 14px; margin-bottom:10px; background:var(--bg-card); border:1px solid var(--border-color); border-radius:8px; box-shadow:0 2px 8px rgba(0,0,0,.06); flex-wrap:wrap }
.bulk-bar-count { font-weight:600; font-size:.85rem }
.bulk-bar-actions { display:flex; gap:6px; flex-wrap:wrap }
.bulk-action { position:relative }
.bulk-menu { display:none; position:absolute; top:calc(100% + 4px); left:0; min-width:180px; max-width:240px; background:var(--bg-card); border:1px solid var(--border-color); border-radius:8px; box-shadow:0 4px 16px rgba(0,0,0,.12); z-index:200; padding:6px }
.bulk-menu.open { display:block }
.bulk-menu-item { display:flex; align-items:center; gap:8px; width:100%; text-align:left; padding:6px 10px; background:none; border:0; border-radius:4px; cursor:pointer; font-size:.85rem; color:var(--text-primary) }
.bulk-menu-item:hover { background:var(--bg-secondary,#f1f5f9) }
.bulk-menu--checks .bulk-menu-scroll { max-height:240px; overflow-y:auto; margin-bottom:8px }
.bulk-menu-check { display:flex; align-items:center; gap:8px; padding:4px 6px; font-size:.85rem; cursor:pointer; border-radius:4px }
.bulk-menu-check:hover { background:var(--bg-secondary,#f1f5f9) }
.label-dot { display:inline-block; width:10px; height:10px; border-radius:50% }
</style>
<script nonce="<?= csp_nonce() ?>">
(function () {
    const PROJECT_ID = <?= (int)$project['id'] ?>;
    const bar      = document.getElementById('bulkBar');
    const allBox   = document.getElementById('bulkAll');
    const countEl  = document.getElementById('bulkCount');
    const checks   = () => Array.from(document.querySelectorAll('.bulk-check'));
    const checked  = () => checks().filter(c => c.checked);
    const ids      = () => checked().map(c => parseInt(c.dataset.tid)).filter(Boolean);

    function refreshBar() {
        const n = checked().length;
        countEl.textContent = String(n);
        bar.style.display = n > 0 ? 'flex' : 'none';
        if (allBox) {
            const all = checks();
            allBox.checked       = n > 0 && n === all.length;
            allBox.indeterminate = n > 0 && n < all.length;
        }
    }
    checks().forEach(c => c.addEventListener('change', refreshBar));
    if (allBox) {
        allBox.addEventListener('click', e => e.stopPropagation());
        allBox.addEventListener('change', () => { checks().forEach(c => c.checked = allBox.checked); refreshBar(); });
    }

    // Toolbar dropdowns
    function closeAllMenus(except) {
        document.querySelectorAll('.bulk-menu').forEach(m => { if (m !== except) m.classList.remove('open'); });
    }
    document.querySelectorAll('[data-bulk]').forEach(btn => {
        btn.addEventListener('click', e => {
            e.stopPropagation();
            const key  = btn.dataset.bulk;
            const menu = bar.querySelector('.bulk-menu[data-menu="' + key + '"]');
            const wasOpen = menu.classList.contains('open');
            closeAllMenus();
            if (!wasOpen) menu.classList.add('open');
        });
    });
    document.addEventListener('click', e => { if (!bar.contains(e.target)) closeAllMenus(); });

    async function postBulk(action, value) {
        if (ids().length === 0) return;
        const base = typeof BASE_URL !== 'undefined' ? BASE_URL : '';
        const csrf = typeof CSRF_TOKEN !== 'undefined' ? CSRF_TOKEN : '';
        const res = await fetch(base + '/api/tasks/bulk-update', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ project_id: PROJECT_ID, task_ids: ids(), action, value, csrf_token: csrf }),
        });
        if (!res.ok) { alert('Update failed'); return; }
        location.reload();
    }

    // Status / Priority / Label-add / Label-remove: simple-value menus
    ['status','priority','label_add','label_remove'].forEach(key => {
        const menu = bar.querySelector('.bulk-menu[data-menu="' + key + '"]');
        if (!menu) return;
        menu.querySelectorAll('.bulk-menu-item').forEach(item => {
            item.addEventListener('click', () => {
                const raw = item.dataset.value;
                const val = (key === 'status' || key === 'label_add' || key === 'label_remove') ? parseInt(raw) : raw;
                postBulk(key, val);
            });
        });
    });

    // Due date
    document.querySelector('[data-action="bulk-apply-due"]')?.addEventListener('click', () => {
        const v = document.getElementById('bulkDueInput').value;
        postBulk('due_date', v || null);
    });
    document.querySelector('[data-action="bulk-clear-due"]')?.addEventListener('click', () => postBulk('due_date', null));

    // Assignees: collect checked users + externals, replace
    document.querySelector('[data-action="bulk-apply-assign"]')?.addEventListener('click', () => {
        const menu = bar.querySelector('.bulk-menu[data-menu="assign"]');
        const users = Array.from(menu.querySelectorAll('input[type=checkbox][data-uid]:checked')).map(c => parseInt(c.dataset.uid));
        const exts  = Array.from(menu.querySelectorAll('input[type=checkbox][data-eid]:checked')).map(c => parseInt(c.dataset.eid));
        postBulk('assign', { users: users, externals: exts });
    });

    // Delete with confirm
    document.querySelector('[data-action="bulk-delete"]')?.addEventListener('click', () => {
        const n = ids().length;
        if (!n) return;
        const msg = (typeof BULK_CONFIRM_DELETE !== 'undefined' ? BULK_CONFIRM_DELETE : 'Delete :n tasks?').replace(':n', String(n));
        if (!confirm(msg)) return;
        postBulk('delete', null);
    });

    // Clear selection
    document.querySelector('[data-action="bulk-clear"]')?.addEventListener('click', () => {
        checks().forEach(c => c.checked = false);
        refreshBar();
    });
})();
</script>
<script nonce="<?= csp_nonce() ?>">const BULK_CONFIRM_DELETE = <?= json_encode(t('bulk_confirm_delete')) ?>;</script>
<?php endif; ?>

<?php if (in_array($myRole, ['owner','manager','member'])): ?>
<!-- ── Inline assignee picker (AJAX) ─────────────────────────────────────── -->
<style>
.assignee-cell { display: flex; align-items: flex-start; gap: 6px; flex-wrap: wrap; min-height: 24px; }
.assignee-cell .assignee-chips { gap: 4px; flex-direction: column; align-items: flex-start; }
.assignee-cell .assignee-chip { padding: 2px 6px 2px 2px; font-size: .72rem; gap: 4px; position: relative; }
.assignee-cell--editable .assignee-chip { padding-right: 18px; }
.assignee-chip-remove {
  position: absolute; top: 50%; right: 3px; transform: translateY(-50%);
  width: 13px; height: 13px; padding: 0; line-height: 1;
  background: transparent; border: none; color: var(--text-muted);
  font-size: 13px; cursor: pointer; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  opacity: 0.35; transition: opacity .15s, color .15s, background .15s;
}
.assignee-cell--editable .assignee-chip:hover .assignee-chip-remove { opacity: 1; }
.assignee-chip-remove:hover { color: var(--color-danger); background: rgba(220, 38, 38, .15); opacity: 1 !important; }
.assignee-chip-remove:focus-visible { opacity: 1; outline: 2px solid var(--color-primary); outline-offset: 1px; }
.assignee-add-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; padding: 0;
  background: transparent; border: 1px dashed var(--border-color);
  border-radius: 50%; color: var(--text-muted);
  cursor: pointer; transition: color .15s, border-color .15s, background .15s;
}
.assignee-add-btn:hover { color: var(--color-primary); border-color: var(--color-primary); background: var(--bg-hover); }
.assignee-popover {
  position: absolute; z-index: 250; min-width: 240px; max-width: 280px;
  background: var(--bg-card); border: 1px solid var(--border-color);
  border-radius: 8px; box-shadow: 0 6px 20px rgba(0,0,0,.14);
  padding: 8px;
}
.assignee-popover input.assignee-search {
  width: 100%; padding: 6px 8px; font-size: .82rem;
  border: 1px solid var(--border-color); border-radius: 4px;
  background: var(--bg-card); color: var(--text-primary);
}
.assignee-popover input.assignee-search:focus { outline: none; border-color: var(--color-primary); }
.assignee-result-list { margin-top: 6px; max-height: 220px; overflow-y: auto; }
.assignee-result {
  display: flex; align-items: center; gap: 8px;
  width: 100%; padding: 5px 6px; border: 0; background: none;
  border-radius: 4px; cursor: pointer; font-size: .8rem;
  color: var(--text-primary); text-align: left;
}
.assignee-result:hover { background: var(--bg-hover); }
.assignee-result-meta { color: var(--text-muted); font-size: .7rem; margin-left: auto; }
.assignee-result-empty { padding: 8px 6px; font-size: .78rem; color: var(--text-muted); text-align: center; }
.assignee-result-loading { padding: 8px 6px; font-size: .78rem; color: var(--text-muted); text-align: center; }
</style>
<script nonce="<?= csp_nonce() ?>">
(function () {
    // CSRF_TOKEN and BASE_URL are declared by the bottom-of-body script in
    // base.php — that script has not been parsed yet when this IIFE runs,
    // so capturing them at init time would freeze empty strings into the
    // closure. Both lookups are wrapped in helpers and resolved at fetch
    // time instead, with the <meta name="csrf-token"> in <head> as a
    // robust fallback (the head is fully parsed before any body inline
    // script can run).
    function csrfNow() {
        if (typeof CSRF_TOKEN !== 'undefined' && CSRF_TOKEN) return CSRF_TOKEN;
        const m = document.querySelector('meta[name="csrf-token"]');
        return m ? m.getAttribute('content') || '' : '';
    }
    function baseNow() {
        return (typeof BASE_URL !== 'undefined') ? BASE_URL : '';
    }
    const PROJECT_ID = <?= (int)$project['id'] ?>;
    const PLACE_HOLD = <?= json_encode(t('search') . '…') ?>;
    const NO_RESULT  = <?= json_encode(t('no_results')) ?>;
    const LOADING    = <?= json_encode(t('loading')) ?>;
    const REMOVE_TT  = <?= json_encode(t('remove')) ?>;

    let openPop = null;

    function escHtml(s) {
        return String(s ?? '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
    }

    function avatarHtml(a, size) {
        const isUser  = !!a.user_id;
        const name    = isUser ? (a.username || '?') : (a.external_name || '?');
        const initial = name.charAt(0).toUpperCase();
        if (isUser && a.avatar) {
            const src = baseNow() + '/api/avatar/' + a.user_id;
            return '<img class="avatar-initials" alt="" src="' + escHtml(src) + '" style="width:' + size + 'px;height:' + size + 'px;border-radius:50%;object-fit:cover">';
        }
        const cls = isUser ? 'avatar-initials' : 'avatar-initials avatar-ext';
        return '<span class="' + cls + '" style="width:' + size + 'px;height:' + size + 'px;font-size:' + Math.floor(size * 0.4) + 'px">'
             + escHtml(initial) + '</span>';
    }

    function chipsHtml(assignees, canEdit) {
        if (!assignees || !assignees.length) return '<span class="text-muted">—</span>';
        let html = '<div class="assignee-chips">';
        for (const a of assignees) {
            const isUser = !!a.user_id;
            const name   = isUser ? (a.username || '') : (a.external_name || '');
            const idAttr = isUser ? ('data-action="remove-user" data-id="' + a.user_id + '"')
                                  : (a.external_id ? ('data-action="remove-ext" data-id="' + a.external_id + '"') : '');
            html += '<div class="assignee-chip' + (isUser ? '' : ' assignee-chip--ext') + '">'
                  + avatarHtml(a, 18)
                  + '<span>' + escHtml(name) + '</span>'
                  + (canEdit && idAttr ? '<button type="button" class="assignee-chip-remove" title="' + escHtml(REMOVE_TT) + '" ' + idAttr + '>×</button>' : '')
                  + '</div>';
        }
        html += '</div>';
        return html;
    }

    function closePopover() {
        if (openPop) { openPop.remove(); openPop = null; }
    }

    // Capture phase: the row's data-href click handler and the cell's
    // data-stop-propagation handler both run in bubble phase, so a
    // bubble-delegated handler on document never sees clicks inside the
    // assignee cell. Capturing fires before either of those, regardless of
    // any stopPropagation calls further down the path.
    document.addEventListener('click', e => {
        if (openPop && !openPop.contains(e.target)) closePopover();
    }, true);
    document.addEventListener('keydown', e => { if (e.key === 'Escape') closePopover(); });

    async function callApi(payload) {
        const csrf = csrfNow();
        payload = Object.assign({}, payload, { csrf_token: csrf });
        const r = await fetch(baseNow() + '/api/tasks/toggle-assignee', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrf },
            body: JSON.stringify(payload),
            credentials: 'same-origin',
        });
        return r.ok ? r.json() : null;
    }

    async function searchUsers(q) {
        if (q.length === 1) return null;
        const csrf = csrfNow();
        const url  = baseNow() + '/api/tasks/assignee-search';
        const body = { q, project_id: PROJECT_ID, csrf_token: csrf };
        try {
            const r = await fetch(url, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrf },
                body: JSON.stringify(body),
                credentials: 'same-origin',
            });
            if (!r.ok) {
                console.warn('[plenvo] assignee-search HTTP', r.status, 'for', body);
                return null;
            }
            return await r.json();
        } catch (err) {
            console.error('[plenvo] assignee-search fetch failed', err, 'for', body);
            return null;
        }
    }

    function renderResults(list, json) {
        if (!json) { list.innerHTML = ''; return; }
        let html = '';
        for (const u of (json.users || [])) {
            html += '<button type="button" class="assignee-result" data-kind="user" data-id="' + u.id + '">'
                  + avatarHtml({ user_id: u.id, username: u.username, avatar: u.avatar }, 18)
                  + '<span>' + escHtml(u.username) + '</span>'
                  + '<span class="assignee-result-meta">' + escHtml(u.email || '') + '</span>'
                  + '</button>';
        }
        for (const x of (json.externals || [])) {
            html += '<button type="button" class="assignee-result" data-kind="ext" data-id="' + x.id + '">'
                  + avatarHtml({ external_name: x.name }, 18)
                  + '<span>' + escHtml(x.name) + '</span>'
                  + '<span class="assignee-result-meta">' + escHtml(x.project_name || '') + '</span>'
                  + '</button>';
        }
        if (!html) html = '<div class="assignee-result-empty">' + escHtml(NO_RESULT) + '</div>';
        list.innerHTML = html;
    }

    function applyResult(cell, json) {
        if (!json || !json.ok) return;
        const chipsWrap = cell.querySelector('.assignee-cell-chips');
        chipsWrap.innerHTML = chipsHtml(json.assignees || [], true);
    }

    // Click handlers — delegated, capture phase (see comment above).
    document.addEventListener('click', async e => {
        // Remove existing assignee chip
        const removeBtn = e.target.closest('.assignee-chip-remove');
        if (removeBtn) {
            e.stopPropagation();
            const cell = removeBtn.closest('.assignee-cell');
            if (!cell) return;
            const taskId = parseInt(cell.dataset.taskId, 10);
            const action = removeBtn.dataset.action;
            const id     = parseInt(removeBtn.dataset.id, 10);
            const payload = { task_id: taskId, action: 'remove' };
            if (action === 'remove-user') payload.user_id = id;
            if (action === 'remove-ext')  payload.external_id = id;
            applyResult(cell, await callApi(payload));
            return;
        }

        // Open the picker
        const addBtn = e.target.closest('.assignee-add-btn');
        if (addBtn) {
            e.stopPropagation();
            const cell = addBtn.closest('.assignee-cell');
            if (!cell) return;
            const taskId = parseInt(cell.dataset.taskId, 10);
            closePopover();

            const pop = document.createElement('div');
            pop.className = 'assignee-popover';
            pop.innerHTML =
                '<input type="text" class="assignee-search" placeholder="' + escHtml(PLACE_HOLD) + '" autocomplete="off">'
              + '<div class="assignee-result-list"></div>';

            // Position the popover under the button.
            const rect = addBtn.getBoundingClientRect();
            pop.style.top  = (window.scrollY + rect.bottom + 4) + 'px';
            pop.style.left = (window.scrollX + rect.left) + 'px';
            document.body.appendChild(pop);
            openPop = pop;

            const input  = pop.querySelector('input');
            const list   = pop.querySelector('.assignee-result-list');
            input.focus();

            // Initial fetch with empty query: shows the full project member
            // roster on open so the user does not have to type to discover
            // who can be assigned.
            list.innerHTML = '<div class="assignee-result-loading">' + escHtml(LOADING) + '</div>';
            (async () => { renderResults(list, await searchUsers('')); })();

            let lastQ = '', timer = null;
            input.addEventListener('input', () => {
                const q = input.value.trim();
                clearTimeout(timer);
                if (q === lastQ) return;
                if (q.length === 1) { return; }
                list.innerHTML = '<div class="assignee-result-loading">' + escHtml(LOADING) + '</div>';
                timer = setTimeout(async () => {
                    const json = await searchUsers(q);
                    lastQ = q;
                    renderResults(list, json);
                }, 180);
            });

            list.addEventListener('click', async ev => {
                const btn = ev.target.closest('.assignee-result');
                if (!btn) return;
                ev.stopPropagation();
                const kind = btn.dataset.kind;
                const id   = parseInt(btn.dataset.id, 10);
                const payload = { task_id: taskId, action: 'add' };
                if (kind === 'user') payload.user_id = id;
                if (kind === 'ext')  payload.external_id = id;
                applyResult(cell, await callApi(payload));
                closePopover();
            });
        }
    }, true);
})();
</script>
<?php endif; ?>
<?php endif; ?>
