import { useState, useMemo } from 'react';
import {
  useGroups,
  useGroup,
  useCreateGroup,
  useDeleteGroup,
  useUpdateGroup,
  useAssignRoleToGroup,
  useRemoveRoleFromGroup,
  useRoles,
} from '../../../api/queries/admin/rbac';
import type { GroupDetail } from '../../../api/queries/admin/rbac';
import { ConfirmDeleteDialog } from '../../../components/admin/ConfirmDeleteDialog';
import { MultiSelectDropdown } from './components/MultiSelectDropdown';
import { hashColor } from './avatar-colors';
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 getGroupMeta(group: GroupDetail, groupMap: Map<string, GroupDetail>): string {
  const parts: string[] = [];
  if (group.parentGroupId) {
    const parent = groupMap.get(group.parentGroupId);
    parts.push(`Child of ${parent?.name ?? 'unknown'}`);
  } else {
    parts.push('Top-level');
  }
  if (group.childGroups.length > 0) {
    parts.push(`${group.childGroups.length} child group${group.childGroups.length !== 1 ? 's' : ''}`);
  }
  parts.push(`${group.members.length} member${group.members.length !== 1 ? 's' : ''}`);
  return parts.join(' · ');
}

function getDescendantIds(groupId: string, allGroups: GroupDetail[]): Set<string> {
  const ids = new Set<string>();
  function walk(id: string) {
    const g = allGroups.find(x => x.id === id);
    if (!g) return;
    for (const child of g.childGroups) {
      if (!ids.has(child.id)) {
        ids.add(child.id);
        walk(child.id);
      }
    }
  }
  walk(groupId);
  return ids;
}

export function GroupsTab() {
  const groups = useGroups();
  const [selectedId, setSelectedId] = useState<string | null>(null);
  const [filter, setFilter] = useState('');
  const [showCreateForm, setShowCreateForm] = useState(false);
  const [newName, setNewName] = useState('');
  const [newParentId, setNewParentId] = useState('');
  const [createError, setCreateError] = useState('');
  const createGroup = useCreateGroup();
  const { data: allRoles } = useRoles();

  const groupDetail = useGroup(selectedId);

  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 = groups.data ?? [];
    if (!filter) return list;
    const lower = filter.toLowerCase();
    return list.filter((g) => g.name.toLowerCase().includes(lower));
  }, [groups.data, filter]);

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

  const detail = groupDetail.data;

  return (
    <>
      <div className={styles.panelHeader}>
        <div>
          <div className={styles.panelTitle}>Groups</div>
          <div className={styles.panelSubtitle}>
            Organise users in nested hierarchies; roles propagate to all members
          </div>
        </div>
        <button type="button" className={styles.btnAdd} onClick={() => setShowCreateForm(true)}>+ Add group</button>
      </div>
      <div className={styles.split}>
        <div className={styles.listPane}>
          <div className={styles.searchBar}>
            <input
              className={styles.searchInput}
              placeholder="Search groups..."
              value={filter}
              onChange={(e) => setFilter(e.target.value)}
            />
          </div>
          {showCreateForm && (
            <div className={styles.createForm}>
              <div className={styles.createFormRow}>
                <label className={styles.createFormLabel}>Name</label>
                <input className={styles.createFormInput} value={newName}
                  onChange={e => { setNewName(e.target.value); setCreateError(''); }}
                  placeholder="Group name" autoFocus />
              </div>
              <div className={styles.createFormRow}>
                <label className={styles.createFormLabel}>Parent</label>
                <select className={styles.createFormSelect} value={newParentId}
                  onChange={e => setNewParentId(e.target.value)}>
                  <option value="">(Top-level)</option>
                  {(groups.data || []).map(g => <option key={g.id} value={g.id}>{g.name}</option>)}
                </select>
              </div>
              {createError && <div className={styles.createFormError}>{createError}</div>}
              <div className={styles.createFormActions}>
                <button type="button" className={styles.createFormBtn}
                  onClick={() => { setShowCreateForm(false); setNewName(''); setNewParentId(''); setCreateError(''); }}>Cancel</button>
                <button type="button" className={styles.createFormBtnPrimary}
                  disabled={!newName.trim() || createGroup.isPending}
                  onClick={() => {
                    createGroup.mutate({ name: newName.trim(), parentGroupId: newParentId || undefined }, {
                      onSuccess: () => { setShowCreateForm(false); setNewName(''); setNewParentId(''); setCreateError(''); },
                      onError: (err) => setCreateError(err instanceof Error ? err.message : 'Failed to create group'),
                    });
                  }}>Create</button>
              </div>
            </div>
          )}
          <div className={styles.entityList}>
            {filtered.map((group) => {
              const isSelected = group.id === selectedId;
              const color = hashColor(group.name);
              return (
                <div
                  key={group.id}
                  className={`${styles.entityItem} ${isSelected ? styles.entityItemSelected : ''}`}
                  onClick={() => setSelectedId(group.id)}
                >
                  <div className={styles.avatar} style={{ background: color.bg, color: color.fg, borderRadius: 8 }}>
                    {getInitials(group.name)}
                  </div>
                  <div className={styles.entityInfo}>
                    <div className={styles.entityName}>{group.name}</div>
                    <div className={styles.entityMeta}>{getGroupMeta(group, groupMap)}</div>
                    <div className={styles.tagList}>
                      {group.directRoles.map((r) => (
                        <span key={r.id} className={`${styles.tag} ${styles.tagRole}`}>
                          {r.name}
                        </span>
                      ))}
                      {group.effectiveRoles
                        .filter((er) => !group.directRoles.some((dr) => dr.id === er.id))
                        .map((r) => (
                          <span
                            key={r.id}
                            className={`${styles.tag} ${styles.tagRole} ${styles.tagInherited}`}
                          >
                            {r.name}
                          </span>
                        ))}
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
        </div>
        <div className={styles.detailPane}>
          {!detail ? (
            <div className={styles.detailEmpty}>
              <span>Select a group to view details</span>
            </div>
          ) : (
            <GroupDetailView
              group={detail}
              groupMap={groupMap}
              allGroups={groups.data || []}
              allRoles={allRoles || []}
              onDeselect={() => setSelectedId(null)}
            />
          )}
        </div>
      </div>
    </>
  );
}

const ADMINS_GROUP_ID = '00000000-0000-0000-0000-000000000010';

function GroupDetailView({
  group,
  groupMap,
  allGroups,
  allRoles,
  onDeselect,
}: {
  group: GroupDetail;
  groupMap: Map<string, GroupDetail>;
  allGroups: GroupDetail[];
  allRoles: Array<{ id: string; name: string }>;
  onDeselect: () => void;
}) {
  const [showDeleteDialog, setShowDeleteDialog] = useState(false);
  const [editingName, setEditingName] = useState(false);
  const [nameValue, setNameValue] = useState(group.name);
  const deleteGroup = useDeleteGroup();
  const updateGroup = useUpdateGroup();
  const assignRole = useAssignRoleToGroup();
  const removeRole = useRemoveRoleFromGroup();

  const isBuiltIn = group.id === ADMINS_GROUP_ID;

  // Reset editing state when group changes
  const [prevGroupId, setPrevGroupId] = useState(group.id);
  if (prevGroupId !== group.id) {
    setPrevGroupId(group.id);
    setEditingName(false);
    setNameValue(group.name);
  }

  const hierarchyLabel = group.parentGroupId
    ? `Child of ${groupMap.get(group.parentGroupId)?.name ?? 'unknown'}`
    : 'Top-level group';

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

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

  const descendantIds = getDescendantIds(group.id, allGroups);
  const parentOptions = allGroups.filter(g => g.id !== group.id && !descendantIds.has(g.id));

  // Build hierarchy tree
  const tree = useMemo(() => {
    const rows: { name: string; depth: number }[] = [];
    // Walk up to find root
    const ancestors: GroupDetail[] = [];
    let current: GroupDetail | undefined = group;
    while (current?.parentGroupId) {
      const parent = groupMap.get(current.parentGroupId);
      if (parent) ancestors.unshift(parent);
      current = parent;
    }
    for (let i = 0; i < ancestors.length; i++) {
      rows.push({ name: ancestors[i].name, depth: i });
    }
    rows.push({ name: group.name, depth: ancestors.length });
    for (const child of group.childGroups) {
      rows.push({ name: child.name, depth: ancestors.length + 1 });
    }
    return rows;
  }, [group, groupMap]);

  const color = hashColor(group.name);

  return (
    <>
      <div className={styles.detailHeader}>
        <div className={styles.detailHeaderInfo}>
          <div className={styles.detailAvatar} style={{ background: color.bg, color: color.fg, borderRadius: 10 }}>
            {getInitials(group.name)}
          </div>
          {editingName ? (
            <input
              className={styles.editNameInput}
              value={nameValue}
              onChange={e => setNameValue(e.target.value)}
              onBlur={() => {
                if (nameValue.trim() && nameValue !== group.name) {
                  updateGroup.mutate({ id: group.id, name: nameValue.trim() });
                }
                setEditingName(false);
              }}
              onKeyDown={e => { if (e.key === 'Enter') e.currentTarget.blur(); if (e.key === 'Escape') { setNameValue(group.name); setEditingName(false); } }}
              autoFocus
            />
          ) : (
            <div className={styles.detailName}
              onClick={() => !isBuiltIn && setEditingName(true)}
              style={{ cursor: isBuiltIn ? 'default' : 'pointer' }}
              title={isBuiltIn ? undefined : 'Click to edit'}>
              {group.name}
            </div>
          )}
          <div className={styles.detailEmail}>{hierarchyLabel}</div>
        </div>
        <button type="button" className={styles.btnDelete}
          onClick={() => setShowDeleteDialog(true)}
          disabled={isBuiltIn || deleteGroup.isPending}
          title={isBuiltIn ? 'Built-in group cannot be deleted' : 'Delete group'}>Delete</button>
      </div>

      <div className={styles.fieldRow}>
        <span className={styles.fieldLabel}>ID</span>
        <span className={`${styles.fieldVal} ${styles.fieldMono}`}>{group.id}</span>
      </div>

      <div className={styles.fieldRow}>
        <span className={styles.fieldLabel}>Parent</span>
        <select className={styles.parentSelect} value={group.parentGroupId || ''}
          onChange={e => updateGroup.mutate({ id: group.id, parentGroupId: e.target.value || null })}>
          <option value="">(Top-level)</option>
          {parentOptions.map(g => <option key={g.id} value={g.id}>{g.name}</option>)}
        </select>
      </div>

      <hr className={styles.divider} />

      <div className={styles.detailSection}>
        <div className={styles.detailSectionTitle}>
          Members <span>direct</span>
        </div>
        {group.members.length === 0 ? (
          <span style={{ fontSize: 12, color: 'var(--text-muted)' }}>No direct members</span>
        ) : (
          group.members.map((m) => (
            <span key={m.userId} className={styles.chip}>
              {m.displayName}
            </span>
          ))
        )}
        {group.childGroups.length > 0 && (
          <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 6 }}>
            + all members of {group.childGroups.map((c) => c.name).join(', ')}
          </div>
        )}
      </div>

      {group.childGroups.length > 0 && (
        <div className={styles.detailSection}>
          <div className={styles.detailSectionTitle}>Child groups</div>
          {group.childGroups.map((c) => (
            <span key={c.id} className={`${styles.chip} ${styles.chipGroup}`}>
              {c.name}
            </span>
          ))}
        </div>
      )}

      <div className={styles.detailSection}>
        <div className={styles.detailSectionTitle}>
          Assigned roles <span>on this group</span>
        </div>
        {group.directRoles.length === 0 ? (
          <span style={{ fontSize: 12, color: 'var(--text-muted)' }}>No roles assigned</span>
        ) : (
          group.directRoles.map((r) => (
            <span key={r.id} className={`${styles.chip} ${styles.chipRole}`}>
              {r.name}
              <button type="button" className={styles.chipRemove}
                onClick={() => removeRole.mutate({ groupId: group.id, roleId: r.id })}
                disabled={removeRole.isPending} title="Remove role">x</button>
            </span>
          ))
        )}
        <MultiSelectDropdown items={availableRoles}
          onApply={async (ids) => { await Promise.allSettled(ids.map(rid => assignRole.mutateAsync({ groupId: group.id, roleId: rid }))); }}
          placeholder="Search roles..." />
        {inheritedRoles.length > 0 && (
          <div className={styles.inheritNote}>
            {group.childGroups.length > 0
              ? `Child groups ${group.childGroups.map((c) => c.name).join(' and ')} inherit these roles, and may additionally carry their own.`
              : 'Roles are inherited from parent groups in the hierarchy.'}
          </div>
        )}
      </div>

      <div className={styles.detailSection}>
        <div className={styles.detailSectionTitle}>Group hierarchy</div>
        {tree.map((node, i) => (
          <div key={i} className={styles.treeRow}>
            {node.depth > 0 && (
              <div className={styles.treeIndent}>
                <div className={styles.treeCorner} />
              </div>
            )}
            {node.name}
          </div>
        ))}
      </div>

      <ConfirmDeleteDialog isOpen={showDeleteDialog} onClose={() => setShowDeleteDialog(false)}
        onConfirm={() => { deleteGroup.mutate(group.id, { onSuccess: () => { setShowDeleteDialog(false); onDeselect(); } }); }}
        resourceName={group.name} resourceType="group" />
    </>
  );
}
