<%- include('top') %>

<script type="text/javascript">
	var userlist;
	var allGroups = [];

	function processGroup(value){
		if (!Array.isArray(value.member)) value.member = value.member ? [value.member] : [];
		if (!Array.isArray(value.owner))  value.owner  = value.owner  ? [value.owner]  : [];
		value.toAdd = userlist.filter(function(user){
			return !value.member.includes(user.dn);
		});
		value.toAddOwner = userlist.filter(function(user){
			return !value.owner.includes(user.dn);
		});
		value.member = value.member.map(function(user){
			return {
				dn: user,
				uid: user.match(/cn=[a-zA-Z0-9\_\-\@\.]+/)[0].replace('cn=', '')
			};
		});
		value.owner = value.owner.map(function(user){
			return {
				dn: user,
				uid: user.match(/cn=[a-zA-Z0-9\_\-\@\.]+/)[0].replace('cn=', '')
			};
		});
		value.memberCount = value.member.length;
		value.createTimestamp = moment(value.createTimestamp, "YYYYMMDDHHmmssZ").fromNow();
		value.modifyTimestamp = moment(value.modifyTimestamp, "YYYYMMDDHHmmssZ").fromNow();
		value.groupCN = value.cn;
		return value;
	}

	// app_sso_service_account is a marker group: membership hides an account
	// from the Users page's People tab entirely (see users.ejs), which is
	// exactly right for a non-person account but has silently made a real
	// person's account look "gone" before (nothing else about it changes).
	// Everywhere else in this dropdown just fires the PUT directly; only
	// this one group gets a confirmation first.
	function addMemberClick(event, groupCN, uid, el){
		event.preventDefault();
		const $el = $(el);
		(async function(){
			if (groupCN === 'app_sso_service_account') {
				const ok = await app.messages.confirm(
					`Mark "${uid}" as a service account? This hides them from the Users page's People tab (Service Accounts tab only) — only do this for a non-person account.`,
					$el.closest('.card'), 'warning'
				);
				if (!ok) return;
			}
			try {
				const data = await app.api.put(`group/${groupCN}/${uid}`, {});
				await addedUser(data.message, groupCN, uid, $el);
			} catch(e) {
				app.messages.action(e.message || 'Failed to add member', $el.closest('.card'), 'danger');
			}
		})();
		return false;
	}

	async function addedUser(message, group, user, $form){
		let data = await app.group.get(group);
		$.scope.groupCard.update('cn', group, processGroup(data.results));
		app.messages.action(message, $("#group-card-"+group), 'success');
		$('a[href="#'+$form.closest('.tab-pane').attr('id')+'"]').tab('show');
		setTimeout(function(group){
			$("body,html").animate({ scrollTop: $("#group-card-" + group).offset().top }, 0);
		}, 400, group);
	}

	function applySort() {
		const sort = $('#groupSort').val();
		const scope = $.scope.groupCard;
		if (sort === 'name-asc')     { scope.__jqOrderBy = 'cn';          scope.__jqOrderReverse = false; }
		if (sort === 'name-desc')    { scope.__jqOrderBy = 'cn';          scope.__jqOrderReverse = true;  }
		if (sort === 'members-desc') { scope.__jqOrderBy = 'memberCount'; scope.__jqOrderReverse = true;  }
		if (sort === 'members-asc')  { scope.__jqOrderBy = 'memberCount'; scope.__jqOrderReverse = false; }
	}

	function matchesSearch(g) {
		const q = $('#groupSearch').val().toLowerCase().trim();
		return !q || g.cn.toLowerCase().includes(q) || (g.description || '').toLowerCase().includes(q);
	}

	function applyFilters() {
		applySort();
		const groups = allGroups.filter(matchesSearch);
		$.scope.groupCard.empty();
		$.scope.groupCard.push(...groups);
		$('#groupCount').text(groups.length + ' of ' + allGroups.length + ' group' + (allGroups.length !== 1 ? 's' : ''));
	}

	async function tableAJAX() {
		let data = await app.group.list();
		allGroups = data.results.map(processGroup);
		applyFilters();
	}

	async function removeMember(groupCN, uid, btn) {
		const $item = $(btn).closest('li');
		$item.addClass('list-group-item-warning');
		const confirmed = await app.messages.confirm(`Remove "${uid}" from "${groupCN}"?`, $item, 'warning');
		if (!confirmed) { $item.removeClass('list-group-item-warning'); return; }
		try {
			const data = await app.api.delete(`group/${groupCN}/${uid}`);
			const groupData = await app.group.get(groupCN);
			$.scope.groupCard.update('cn', groupCN, processGroup(groupData.results));
			app.messages.action(data.message, $('#group-card-' + groupCN), 'success');
		} catch(e) {
			$item.removeClass('list-group-item-warning');
			app.messages.action(e.message || 'Failed to remove member', $('#group-card-' + groupCN), 'danger');
		}
	}

	async function removeOwner(groupCN, uid, btn) {
		const $item = $(btn).closest('li');
		$item.addClass('list-group-item-warning');
		const confirmed = await app.messages.confirm(`Remove "${uid}" as owner of "${groupCN}"?`, $item, 'warning');
		if (!confirmed) { $item.removeClass('list-group-item-warning'); return; }
		try {
			const data = await app.api.delete(`group/owner/${groupCN}/${uid}`);
			const groupData = await app.group.get(groupCN);
			$.scope.groupCard.update('cn', groupCN, processGroup(groupData.results));
			app.messages.action(data.message, $('#group-card-' + groupCN), 'success');
		} catch(e) {
			$item.removeClass('list-group-item-warning');
			app.messages.action(e.message || 'Failed to remove owner', $('#group-card-' + groupCN), 'danger');
		}
	}

	async function deleteGroup(cn, btn) {
		const $card = $(btn).closest('.card');
		const confirmed = await app.messages.confirm(`Delete group "${cn}"?`, $card, 'danger');
		if (!confirmed) return;
		try {
			await app.api.delete(`group/${cn}`);
			$.scope.groupCard.remove('cn', cn);
		} catch(e) {
			app.messages.action(e.message || 'Failed to delete group', $card, 'danger');
		}
	}

	app.auth.forceLogin('app_sso_admin');

	$(document).ready(async function(){
		userlist = (await app.user.list()).results;
		tableAJAX();
	});
</script>
<div class="container mt-4">
	
	<div class="d-flex flex-wrap gap-2 align-items-center">
		<div class="input-group" style="flex: 1 1 200px;">
			<span class="input-group-text"><i class="fa-solid fa-magnifying-glass"></i></span>
			<input type="text" id="groupSearch" class="form-control" placeholder="Search groups…" oninput="applyFilters()">
		</div>
		<select id="groupSort" class="form-select" style="width:auto; min-width:175px" onchange="applyFilters()">
			<option value="name-asc">Name A → Z</option>
			<option value="name-desc">Name Z → A</option>
			<option value="members-desc">Most members</option>
			<option value="members-asc">Fewest members</option>
		</select>
		<span id="groupCount" class="text-muted text-nowrap small"></span>
	</div>
	<div class="row row-cols-1 row-cols-md-3 g-4 mt-0">
		<div class="col">
			<div class="card shadow">
				<div class="card-header">
					<i class="fa-solid fa-object-group"></i>
					Add new group
					<a href="/docs/accounts" class="text-reset float-end" title="Help"><i class="fa-solid fa-circle-question"></i></a>
				</div>
				<div class="card-header actionMessage" style="display:none"></div>
				<div class="card-body">
					<form action="group/" method="post" onsubmit="formAJAX(this)" evalAJAX="tableAJAX('')">
						<div class="mb-3">
							<label class="form-label">Name</label>
							<input type="text" class="form-control shadow" name="name" placeholder="app_gitea_admin" validate=":3" />
						</div>

						<div class="mb-3">
							<label class="form-label">Description</label>
							<textarea class="form-control shadow" name="description" placeholder="Admin group for gitea app" validate=":3"></textarea>
						</div>

						<button type="submit" class="btn btn-outline-dark">Add</button>
					</form>
				</div>
			</div>
		</div>
		<div class="col" jq-repeat="groupCard" jq-index-key="cn" jr-order-by="cn" id="group-card-{{cn}}">
			<div class="card shadow col">
				<div class="card-header">
					<h5>
						<i class="fa-solid fa-arrows-down-to-people"></i>
						Group: {{ cn }}
						<a href="/docs/accounts" class="text-reset float-end" title="Help"><i class="fa-solid fa-circle-question"></i></a>
					</h5>
					<ul class="nav nav-tabs card-header-tabs" id="myTab" role="tablist">
						<li class="nav-item">
							<a class="nav-link active" id="group-members-tab-{{cn}}" data-bs-toggle="tab" data-bs-target="#group-memmbers-{{cn}}" href="#group-memmbers-{{cn}}" role="tab" aria-controls="member" aria-selected="true">
								<i class="fa-solid fa-users"></i>
								Members
							</a>
						</li>
						<li class="nav-item">
							<a class="nav-link" id="group-admins-tab-{{cn}}" data-bs-toggle="tab" data-bs-target="#group-admins-{{cn}}" href="#group-admins-{{cn}}" role="tab" aria-controls="admin" aria-selected="false">
								<i class="fa-solid fa-user-tie"></i>
								Owners
							</a>
						</li>
						<li class="nav-item float-end">
							
						</li>
					</ul>

				</div>
				<div class="card-header actionMessage" style="display:none"></div>
				<div class="card-body">
					<p>
						{{ description }}
					</p>
					<div class="tab-content" id="myTabContent">			  
						<div class="tab-pane fade show active" id="group-memmbers-{{cn}}" role="tabpanel" aria-labelledby="member-tab">
							<p>	
								<ul class="list-group">
								{{ #member }}
									<li id="group-card-{{cn}}-{{uid}}" class="list-group-item shadow">
										<i class="fa-solid fa-user"></i> {{ uid }}
										<button type="button" onclick="removeMember('{{groupCN}}', '{{uid}}', this)" class="btn btn-sm btn-danger float-end">
											<i class="fa-solid fa-user-slash"></i>
										</button>
									</li>
								{{ /member }}
								</ul>
							</p>
							<div class="dropdown">
								<button class="btn btn-secondary dropdown-toggle" type="button" id="group_add_member" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
									<i class="fa-solid fa-user-plus"></i>
								</button>
								<div class="dropdown-menu shadow-lg" aria-labelledby="group_add_member">
								{{ #toAdd }}{{#.}}
									<a class="dropdown-item" href="#" onclick="return addMemberClick(event, '{{groupCN}}', '{{uid}}', this);">
										<i class="fa-solid fa-user"></i> {{uid}}
									</a>
								{{/.}}{{ /toAdd }}
								
								</div>
							</div>
						</div>

						<div class="tab-pane fade" id="group-admins-{{cn}}" role="tabpanel" aria-labelledby="admin-tab">
							<p>
								<ul class="list-group">
								{{ #owner }}
									<li class="list-group-item shadow">
										<i class="fa-solid fa-user"></i> {{ uid }}
										<button type="button" onclick="removeOwner('{{groupCN}}', '{{uid}}', this)" class="btn btn-sm btn-danger float-end">
											<i class="fa-solid fa-user-slash"></i>
										</button>
									</li>
								{{ /owner }}
								</ul>
							</p>

							<div class="dropdown float-start">
								<button class="btn btn-secondary dropdown-toggle" type="button" id="group_add_admin" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
									<i class="fa-solid fa-user-plus"></i>
								</button>
								<div class="dropdown-menu shadow-lg" aria-labelledby="group_add_admin">
								{{ #toAddOwner }}{{#.}}
									<a class="dropdown-item" action="group/owner/{{groupCN}}/{{uid}}" method="put" onclick="formAJAX(this)" evalAJAX="addedUser(data.message, '{{groupCN}}', '{{uid}}', $form)">
										<i class="fa-solid fa-user"></i> {{uid}}
									</a>
								{{/.}}{{ /toAddOwner }}
								
								</div>
							</div>

						</div>
					</div>
				</div>
				<div class="card-footer">
					<div class="float-end">
						<button type="button" onclick="" class="btn btn-warning btn-lg shadow">
							<i class="fa-solid fa-edit"></i>
						</button>
						<button type="button" onclick="deleteGroup('{{cn}}', this)" class="btn btn-danger btn-lg">
							<i class="fa-solid fa-trash"></i>
						</button>
					</div>
					<div>
						Created: {{createTimestamp}}<br />
						Last Modified: {{modifyTimestamp}}
					</div>
				</div>
			</div>
		</div>
	</div>

</div>
<%- include('bottom') %>
