import { useState, useMemo } from 'react';
import { useUsers, useGroups, useRoles, useDeleteUser, useAddUserToGroup, useRemoveUserFromGroup, useAssignRoleToUser, useRemoveRoleFromUser } from '../../../api/queries/admin/rbac';
import type { UserDetail, GroupDetail, RoleDetail } from '../../../api/queries/admin/rbac';
import { ConfirmDeleteDialog } from '../../../components/admin/ConfirmDeleteDialog';
import { MultiSelectDropdown } from './components/MultiSelectDropdown';
import { useAuthStore } from '../../../auth/auth-store';
import styles from './RbacPage.module.css';

function getInitials(name: string): string {
  const parts = name.trim().split(/\s+/);
  if (parts.length >= 2) return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
  return name.slice(0, 2).toUpperCase();
}

function buildGroupPath(user: UserDetail, groupMap: Map<string, GroupDetail>): string {
  if (user.directGroups.length === 0) return '(no groups)';
  const names = user.directGroups.map((g) => g.name);
  // Try to find a parent -> child path
  for (const g of user.directGroups) {
    const detail = groupMap.get(g.id);
    if (detail?.parentGroupId) {
      const parent = groupMap.get(detail.parentGroupId);
      if (parent) return `${parent.name} > ${g.name}`;
    }
  }
  return names.join(', ');
}

export function UsersTab() {
  const users = useUsers();
  const groups = useGroups();
  const { data: allRoles } = useRoles();
  const [selected, setSelected] = useState<string | null>(null);
  const [filter, setFilter] = useState('');

  const groupMap = useMemo(() => {
    const map = new Map<string, GroupDetail>();
    for (const g of groups.data ?? []) {
      map.set(g.id, g);
    }
    return map;
  }, [groups.data]);

  const filtered = useMemo(() => {
    const list = users.data ?? [];
    if (!filter) return list;
    const lower = filter.toLowerCase();
    return list.filter(
      (u) =>
        u.displayName.toLowerCase().includes(lower) ||
        u.email.toLowerCase().includes(lower) ||
        u.userId.toLowerCase().includes(lower)
    );
  }, [users.data, filter]);

  const selectedUser = useMemo(
    () => (users.data ?? []).find((u) => u.userId === selected) ?? null,
    [users.data, selected]
  );

  if (users.isLoading) {
    return <div className={styles.loading}>Loading...</div>;
  }

  return (
    <>
      <div className={styles.panelHeader}>
        <div>
          <div className={styles.panelTitle}>Users</div>
          <div className={styles.panelSubtitle}>
            Manage identities, group membership and direct roles
          </div>
        </div>
      </div>
      <div className={styles.split}>
        <div className={styles.listPane}>
          <div className={styles.searchBar}>
            <input
              className={styles.searchInput}
              placeholder="Search users..."
              value={filter}
              onChange={(e) => setFilter(e.target.value)}
            />
          </div>
          <div className={styles.entityList}>
            {filtered.map((user) => {
              const isSelected = user.userId === selected;
              return (
                <div
                  key={user.userId}
                  className={`${styles.entityItem} ${isSelected ? styles.entityItemSelected : ''}`}
                  onClick={() => setSelected(user.userId)}
                >
                  <div className={`${styles.avatar} ${styles.avatarUser}`}>
                    {getInitials(user.displayName)}
                  </div>
                  <div className={styles.entityInfo}>
                    <div className={styles.entityName}>
                      {user.displayName}
                      {user.provider !== 'local' && (
                        <span className={styles.oidcBadge}>{user.provider}</span>
                      )}
                    </div>
                    <div className={styles.entityMeta}>
                      {user.email} · {buildGroupPath(user, groupMap)}
                    </div>
                    <div className={styles.tagList}>
                      {user.directRoles.map((r) => (
                        <span key={r.id} className={`${styles.tag} ${styles.tagRole}`}>
                          {r.name}
                        </span>
                      ))}
                      {user.effectiveRoles
                        .filter((er) => !user.directRoles.some((dr) => dr.id === er.id))
                        .map((r) => (
                          <span
                            key={r.id}
                            className={`${styles.tag} ${styles.tagRole} ${styles.tagInherited}`}
                          >
                            {r.name}
                          </span>
                        ))}
                      {user.directGroups.map((g) => (
                        <span key={g.id} className={`${styles.tag} ${styles.tagGroup}`}>
                          {g.name}
                        </span>
                      ))}
                    </div>
                  </div>
                  <div
                    className={`${styles.statusDot} ${styles.statusActive}`}
                  />
                </div>
              );
            })}
          </div>
        </div>
        <div className={styles.detailPane}>
          {!selectedUser ? (
            <div className={styles.detailEmpty}>
              <span>Select a user to view details</span>
            </div>
          ) : (
            <UserDetailView
              user={selectedUser}
              groupMap={groupMap}
              allGroups={groups.data || []}
              allRoles={allRoles || []}
              onDeselect={() => setSelected(null)}
            />
          )}
        </div>
      </div>
    </>
  );
}

function UserDetailView({
  user,
  groupMap,
  allGroups,
  allRoles,
  onDeselect,
}: {
  user: UserDetail;
  groupMap: Map<string, GroupDetail>;
  allGroups: GroupDetail[];
  allRoles: RoleDetail[];
  onDeselect: () => void;
}) {
  const [showDeleteDialog, setShowDeleteDialog] = useState(false);
  const deleteUserMut = useDeleteUser();
  const addToGroup = useAddUserToGroup();
  const removeFromGroup = useRemoveUserFromGroup();
  const assignRole = useAssignRoleToUser();
  const removeRole = useRemoveRoleFromUser();

  const accessToken = useAuthStore((s) => s.accessToken);
  const currentUserId = accessToken ? JSON.parse(atob(accessToken.split('.')[1])).sub : null;
  const isSelf = currentUserId === user.userId;

  // Build group tree for this user
  const groupTree = useMemo(() => {
    const tree: { name: string; depth: number; annotation: string }[] = [];
    for (const g of user.directGroups) {
      const detail = groupMap.get(g.id);
      if (detail?.parentGroupId) {
        const parent = groupMap.get(detail.parentGroupId);
        if (parent && !tree.some((t) => t.name === parent.name)) {
          tree.push({ name: parent.name, depth: 0, annotation: '' });
        }
        tree.push({ name: g.name, depth: 1, annotation: 'child group' });
      } else {
        tree.push({ name: g.name, depth: 0, annotation: '' });
      }
    }
    return tree;
  }, [user, groupMap]);

  const inheritedRoles = user.effectiveRoles.filter(
    (er) => !user.directRoles.some((dr) => dr.id === er.id)
  );

  const availableGroups = allGroups
    .filter((g) => !user.directGroups.some((dg) => dg.id === g.id))
    .map((g) => ({ id: g.id, label: g.name }));

  const availableRoles = allRoles
    .filter((r) => !user.directRoles.some((dr) => dr.id === r.id))
    .map((r) => ({ id: r.id, label: r.name }));

  return (
    <>
      <div className={styles.detailHeader}>
        <div className={styles.detailHeaderInfo}>
          <div className={`${styles.detailAvatar} ${styles.avatarUser}`}>
            {getInitials(user.displayName)}
          </div>
          <div className={styles.detailName}>
            {user.displayName}
            {user.provider !== 'local' && (
              <span className={styles.oidcBadge}>{user.provider}</span>
            )}
          </div>
          <div className={styles.detailEmail}>{user.email}</div>
        </div>
        <button
          type="button"
          className={styles.btnDelete}
          onClick={() => setShowDeleteDialog(true)}
          disabled={isSelf || deleteUserMut.isPending}
          title={isSelf ? 'Cannot delete your own account' : 'Delete user'}
        >
          Delete
        </button>
      </div>

      <div className={styles.fieldRow}>
        <span className={styles.fieldLabel}>Status</span>
        <span className={styles.fieldVal} style={{ color: 'var(--green)', fontSize: 12 }}>
          Active
        </span>
      </div>
      <div className={styles.fieldRow}>
        <span className={styles.fieldLabel}>ID</span>
        <span className={`${styles.fieldVal} ${styles.fieldMono}`}>{user.userId}</span>
      </div>
      <div className={styles.fieldRow}>
        <span className={styles.fieldLabel}>Created</span>
        <span className={styles.fieldVal}>{new Date(user.createdAt).toLocaleString()}</span>
      </div>

      <hr className={styles.divider} />

      <div className={styles.detailSection}>
        <div className={styles.detailSectionTitle}>
          Group membership <span>direct only</span>
        </div>
        {user.directGroups.length === 0 ? (
          <span style={{ fontSize: 12, color: 'var(--text-muted)' }}>No group membership</span>
        ) : (
          user.directGroups.map((g) => (
            <span key={g.id} className={`${styles.chip} ${styles.chipGroup}`}>
              {g.name}
              <button
                type="button"
                className={styles.chipRemove}
                onClick={() => removeFromGroup.mutate({ userId: user.userId, groupId: g.id })}
                disabled={removeFromGroup.isPending}
                title="Remove from group"
              >
                x
              </button>
            </span>
          ))
        )}
        <MultiSelectDropdown
          items={availableGroups}
          onApply={async (ids) => {
            await Promise.allSettled(
              ids.map((gid) => addToGroup.mutateAsync({ userId: user.userId, groupId: gid }))
            );
          }}
          placeholder="Search groups..."
        />
      </div>

      <div className={styles.detailSection}>
        <div className={styles.detailSectionTitle}>
          Effective roles <span>direct + inherited</span>
        </div>
        {user.directRoles.map((r) => (
          <span key={r.id} className={`${styles.chip} ${styles.chipRole}`}>
            {r.name}
            <button
              type="button"
              className={styles.chipRemove}
              onClick={() => removeRole.mutate({ userId: user.userId, roleId: r.id })}
              disabled={removeRole.isPending}
              title="Remove role"
            >
              x
            </button>
          </span>
        ))}
        {inheritedRoles.map((r) => (
          <span key={r.id} className={`${styles.chip} ${styles.chipRole} ${styles.chipInherited}`}>
            {r.name}
            <span className={styles.chipSource}>
              {r.source ? `\u2191 ${r.source}` : ''}
            </span>
          </span>
        ))}
        {inheritedRoles.length > 0 && (
          <div className={styles.inheritNote}>
            Dashed roles are inherited transitively through group membership.
          </div>
        )}
        <MultiSelectDropdown
          items={availableRoles}
          onApply={async (ids) => {
            await Promise.allSettled(
              ids.map((rid) => assignRole.mutateAsync({ userId: user.userId, roleId: rid }))
            );
          }}
          placeholder="Search roles..."
        />
      </div>

      {groupTree.length > 0 && (
        <div className={styles.detailSection}>
          <div className={styles.detailSectionTitle}>Group tree</div>
          {groupTree.map((node, i) => (
            <div key={i} className={styles.treeRow}>
              {node.depth > 0 && (
                <div className={styles.treeIndent}>
                  <div className={styles.treeCorner} />
                </div>
              )}
              {node.name}
              {node.annotation && (
                <span style={{ fontSize: 10, color: 'var(--text-muted)', marginLeft: 4 }}>
                  {node.annotation}
                </span>
              )}
            </div>
          ))}
        </div>
      )}

      <ConfirmDeleteDialog
        isOpen={showDeleteDialog}
        onClose={() => setShowDeleteDialog(false)}
        onConfirm={() => {
          deleteUserMut.mutate(user.userId, {
            onSuccess: () => {
              setShowDeleteDialog(false);
              onDeselect();
            },
          });
        }}
        resourceName={user.displayName || user.userId}
        resourceType="user"
      />
    </>
  );
}
