<template>
  <div class="space-y-4">
    <!-- Loading State -->
    <div
      v-if="isLoading"
      class="mt-16 text-center text-4xl bg-slate-400 text-white w-14 py-2.5 rounded-full mx-auto"
    >
      <font-awesome icon="spinner" class="fa-spin-pulse" />
    </div>

    <!-- Members List -->

    <div v-else>
      <div class="text-center text-red-600 my-4">
        {{ decryptionErrorMessage() }}
      </div>

      <div v-if="missingMyself" class="py-4 text-red-600">
        You are not currently admitted by the organizer.
      </div>
      <div v-if="!firstName" class="py-4 text-red-600">
        Your name is not set, so others may not recognize you. Reload this page
        to set it.
      </div>

      <ul class="list-disc text-sm ps-4 space-y-2 mb-4">
        <li
          v-if="membersToShow().length > 0 && showOrganizerTools && isOrganizer"
        >
          Click
          <font-awesome icon="circle-plus" class="text-blue-500 text-sm" />
          /
          <font-awesome icon="circle-minus" class="text-rose-500 text-sm" />
          to add/remove them to/from the meeting.
        </li>
        <li v-if="membersToShow().length > 0">
          Click
          <font-awesome icon="circle-user" class="text-green-600 text-sm" />
          to add them to your contacts.
        </li>
      </ul>

      <div class="flex justify-between">
        <!-- 
        always have at least one refresh button even without members in case the organizer 
         changes the password 
         -->
        <button
          class="text-sm bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-3 py-1.5 rounded-md"
          title="Refresh members list now"
          @click="manualRefresh"
        >
          <font-awesome icon="rotate" :class="{ 'fa-spin': isLoading }" />
          Refresh
          <span class="text-xs">({{ countdownTimer }}s)</span>
        </button>
      </div>
      <ul
        v-if="membersToShow().length > 0"
        class="border-t border-slate-300 my-2"
      >
        <li
          v-for="member in membersToShow()"
          :key="member.member.memberId"
          :class="[
            'border-b px-2 sm:px-3 py-1.5',
            {
              'bg-blue-50 border-t border-blue-300 -mt-[1px]':
                !member.member.admitted && isOrganizer,
            },
            { 'border-slate-300': member.member.admitted },
          ]"
        >
          <div class="flex items-center gap-2 justify-between">
            <div class="flex items-center gap-1 overflow-hidden">
              <h3
                :class="[
                  'font-semibold truncate',
                  { 'text-slate-500': !member.member.admitted && isOrganizer },
                ]"
              >
                <font-awesome
                  v-if="member.member.memberId === members[0]?.memberId"
                  icon="crown"
                  class="fa-fw text-amber-400"
                />
                <font-awesome
                  v-if="!member.member.admitted && isOrganizer"
                  icon="hourglass-half"
                  class="fa-fw text-slate-400"
                />
                {{ member.name || unnamedMember }}
              </h3>
              <div
                v-if="!getContactFor(member.did) && member.did !== activeDid"
                class="flex items-center gap-1.5 ms-1"
              >
                <button
                  class="btn-add-contact"
                  title="Add as contact"
                  @click="addAsContact(member)"
                >
                  <font-awesome icon="circle-user" />
                </button>

                <button
                  class="btn-info-contact"
                  title="Contact Info"
                  @click="
                    informAboutAddingContact(
                      getContactFor(member.did) !== undefined,
                    )
                  "
                >
                  <font-awesome icon="circle-info" />
                </button>
              </div>
            </div>
            <span
              v-if="
                showOrganizerTools && isOrganizer && member.did !== activeDid
              "
              class="flex items-center gap-1.5"
            >
              <button
                :class="
                  member.member.admitted
                    ? 'btn-admission-remove'
                    : 'btn-admission-add'
                "
                :title="
                  member.member.admitted ? 'Remove member' : 'Admit member'
                "
                @click="checkWhetherContactBeforeAdmitting(member)"
              >
                <font-awesome
                  :icon="
                    member.member.admitted ? 'circle-minus' : 'circle-plus'
                  "
                />
              </button>

              <button
                class="btn-info-admission"
                title="Admission Info"
                @click="informAboutAdmission()"
              >
                <font-awesome icon="circle-info" />
              </button>
            </span>
          </div>
          <p class="text-xs text-gray-600 truncate">
            {{ member.did }}
          </p>
        </li>
      </ul>

      <div v-if="membersToShow().length > 0" class="flex justify-between">
        <!-- 
        always have at least one refresh button even without members in case the organizer 
         changes the password 
         -->
        <button
          class="text-sm bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-3 py-1.5 rounded-md"
          title="Refresh members list now"
          @click="manualRefresh"
        >
          <font-awesome icon="rotate" :class="{ 'fa-spin': isLoading }" />
          Refresh
          <span class="text-xs">({{ countdownTimer }}s)</span>
        </button>
      </div>

      <p v-if="members.length === 0" class="text-gray-500 py-4">
        No members have joined this meeting yet
      </p>
    </div>
  </div>

  <!-- Admit Pending Members Dialog Component -->
  <AdmitPendingMembersDialog
    :visible="showAdmitPendingDialog"
    :pending-members-data="pendingMembersData"
    :active-did="activeDid"
    :api-server="apiServer"
    @close="closeAdmitPendingDialog"
    @success="onAdmitPendingSuccess"
  />

  <!-- Set Visibility Dialog Component -->
  <SetBulkVisibilityDialog
    :visible="showSetVisibilityDialog"
    :members-data="visibilityDialogMembers"
    :active-did="activeDid"
    :api-server="apiServer"
    @close="closeSetVisibilityDialog"
  />
</template>

<script lang="ts">
import { Component, Vue, Prop, Emit } from "vue-facing-decorator";

import {
  errorStringForLog,
  getHeaders,
  register,
  serverMessageForUser,
} from "../libs/endorserServer";
import { decryptMessage } from "../libs/crypto";
import { Contact } from "../db/tables/contacts";
import * as libsUtil from "../libs/util";
import { NotificationIface } from "../constants/app";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
import {
  NOTIFY_ADD_CONTACT_FIRST,
  NOTIFY_CONTINUE_WITHOUT_ADDING,
} from "@/constants/notifications";
import { SOMEONE_UNNAMED } from "@/constants/entities";
import SetBulkVisibilityDialog from "./SetBulkVisibilityDialog.vue";
import AdmitPendingMembersDialog from "./AdmitPendingMembersDialog.vue";

interface Member {
  admitted: boolean;
  content: string;
  memberId: number;
}

interface DecryptedMember {
  member: Member;
  name: string;
  did: string;
  isRegistered: boolean;
}

@Component({
  components: {
    SetBulkVisibilityDialog,
    AdmitPendingMembersDialog,
  },
  mixins: [PlatformServiceMixin],
})
export default class MembersList extends Vue {
  $notify!: (notification: NotificationIface, timeout?: number) => void;

  notify!: ReturnType<typeof createNotifyHelpers>;
  libsUtil = libsUtil;

  @Prop({ required: true }) password!: string;
  @Prop({ default: false }) showOrganizerTools!: boolean;

  // Emit methods using @Emit decorator
  @Emit("error")
  emitError(message: string) {
    return message;
  }

  decryptedMembers: DecryptedMember[] = [];
  firstName = "";
  isLoading = true;
  isOrganizer = false;
  members: Member[] = [];
  missingPassword = false;
  missingMyself = false;
  activeDid = "";
  apiServer = "";

  // Admit Pending Members Dialog state
  showAdmitPendingDialog = false;
  pendingMembersData: Array<{
    did: string;
    name: string;
    isContact: boolean;
    member: { memberId: string };
  }> = [];
  admitDialogDismissed = false;
  isManualRefresh = false;

  // Set Visibility Dialog state
  showSetVisibilityDialog = false;
  visibilityDialogMembers: Array<{
    did: string;
    name: string;
    isContact: boolean;
    member: { memberId: string };
  }> = [];
  contacts: Array<Contact> = [];

  // Auto-refresh functionality
  countdownTimer = 10;
  autoRefreshInterval: NodeJS.Timeout | null = null;

  // Track previous visibility members to detect changes
  previousVisibilityMembers: string[] = [];

  /**
   * Get the unnamed member constant
   */
  get unnamedMember(): string {
    return SOMEONE_UNNAMED;
  }

  async created() {
    this.notify = createNotifyHelpers(this.$notify);

    const settings = await this.$accountSettings();

    // Get activeDid from active_identity table (single source of truth)
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const activeIdentity = await (this as any).$getActiveIdentity();
    this.activeDid = activeIdentity.activeDid || "";

    this.apiServer = settings.apiServer || "";
    this.firstName = settings.firstName || "";
    await this.fetchMembers();
    await this.loadContacts();

    // Start auto-refresh
    this.startAutoRefresh();

    // Check if we should show the admit pending members dialog first
    this.checkAndShowAdmitPendingDialog();

    // If no pending members, check for visibility dialog
    if (!this.showAdmitPendingDialog) {
      this.checkAndShowVisibilityDialog();
    }
  }

  async refreshData() {
    // Force refresh both contacts and members
    await this.loadContacts();
    await this.fetchMembers();

    // Check if we should show the admit pending members dialog first
    this.checkAndShowAdmitPendingDialog();

    // If no pending members, check for visibility dialog
    if (!this.showAdmitPendingDialog) {
      this.checkAndShowVisibilityDialog();
    }
  }

  async fetchMembers() {
    try {
      this.isLoading = true;
      const headers = await getHeaders(this.activeDid);
      const response = await this.axios.get(
        `${this.apiServer}/api/partner/groupOnboardMembers`,
        { headers },
      );

      if (response.data && response.data.data) {
        this.members = response.data.data;
        await this.decryptMemberContents();
      }
    } catch (error) {
      this.$logAndConsole(
        "Error fetching members: " + errorStringForLog(error),
        true,
      );
      this.emitError(serverMessageForUser(error) || "Failed to fetch members.");
    } finally {
      this.isLoading = false;
    }
  }

  async decryptMemberContents() {
    this.decryptedMembers = [];

    if (!this.password) {
      this.missingPassword = true;
      return;
    }

    let isFirstEntry = true,
      foundMyself = false;
    for (const member of this.members) {
      try {
        const decryptedContent = await decryptMessage(
          member.content,
          this.password,
        );
        const content = JSON.parse(decryptedContent);

        this.decryptedMembers.push({
          member: member,
          name: content.name,
          did: content.did,
          isRegistered: !!content.isRegistered,
        });
        if (isFirstEntry && content.did === this.activeDid) {
          this.isOrganizer = true;
        }
        if (content.did === this.activeDid) {
          foundMyself = true;
        }
      } catch (error) {
        // do nothing, relying on the count of members to determine if there was an error
      }
      isFirstEntry = false;
    }
    this.missingMyself = !foundMyself;
  }

  decryptionErrorMessage(): string {
    if (this.isOrganizer) {
      if (this.decryptedMembers.length < this.members.length) {
        return "Some members have data that cannot be decrypted with that password.";
      } else {
        // the lists must be equal
        return "";
      }
    } else {
      // non-organizers should only see problems if the first (organizer) member is not decrypted
      if (
        this.decryptedMembers.length === 0 ||
        this.decryptedMembers[0].member.memberId !== this.members[0].memberId
      ) {
        return "Your password is not the same as the organizer. Retry or have them check their password.";
      } else {
        // the first (organizer) member was decrypted OK
        return "";
      }
    }
  }

  membersToShow(): DecryptedMember[] {
    let members: DecryptedMember[] = [];

    if (this.isOrganizer) {
      if (this.showOrganizerTools) {
        members = this.decryptedMembers;
      } else {
        members = this.decryptedMembers.filter(
          (member: DecryptedMember) => member.member.admitted,
        );
      }
    } else {
      // non-organizers only get visible members from server
      members = this.decryptedMembers;
    }

    // Sort members according to priority:
    // 1. Organizer at the top
    // 2. Non-admitted members next
    // 3. Everyone else after
    return members.sort((a, b) => {
      // Check if either member is the organizer (first member in original list)
      const aIsOrganizer = a.member.memberId === this.members[0]?.memberId;
      const bIsOrganizer = b.member.memberId === this.members[0]?.memberId;

      // Organizer always comes first
      if (aIsOrganizer && !bIsOrganizer) return -1;
      if (!aIsOrganizer && bIsOrganizer) return 1;

      // If both are organizers or neither are organizers, sort by admission status
      if (aIsOrganizer && bIsOrganizer) return 0; // Both organizers, maintain original order

      // Non-admitted members come before admitted members
      if (!a.member.admitted && b.member.admitted) return -1;
      if (a.member.admitted && !b.member.admitted) return 1;

      // If admission status is the same, maintain original order
      return 0;
    });
  }

  informAboutAdmission() {
    this.notify.info(
      "This is to register people in Time Safari and to admit them to the meeting. A (+) symbol means they are not yet admitted and you can register and admit them. A (-) symbol means you can remove them, but they will stay registered.",
      TIMEOUTS.VERY_LONG,
    );
  }

  informAboutAddingContact(contactImportedAlready: boolean) {
    if (contactImportedAlready) {
      this.notify.info(
        "They are in your contacts. To remove them, use the contacts page.",
        TIMEOUTS.VERY_LONG,
      );
    } else {
      this.notify.info(
        "This is to add them to your contacts. To remove them later, use the contacts page.",
        TIMEOUTS.VERY_LONG,
      );
    }
  }

  async loadContacts() {
    this.contacts = await this.$getAllContacts();
  }

  getContactFor(did: string): Contact | undefined {
    return this.contacts.find((contact) => contact.did === did);
  }

  getPendingMembers() {
    return this.decryptedMembers
      .filter((member) => {
        // Exclude the current user
        if (member.did === this.activeDid) {
          return false;
        }
        // Only include non-admitted members
        return !member.member.admitted;
      })
      .map((member) => ({
        did: member.did,
        name: member.name,
        isContact: !!this.getContactFor(member.did),
        member: {
          memberId: member.member.memberId.toString(),
        },
      }));
  }

  getMembersForVisibility() {
    const membersForVisibility = this.decryptedMembers
      .filter((member) => {
        // Exclude the current user
        if (member.did === this.activeDid) {
          return false;
        }

        const contact = this.getContactFor(member.did);

        // Include members who:
        // 1. Haven't been added as contacts yet, OR
        // 2. Are contacts but don't have visibility set (seesMe property)
        return !contact || !contact.seesMe;
      })
      .map((member) => ({
        did: member.did,
        name: member.name,
        isContact: !!this.getContactFor(member.did),
        member: {
          memberId: member.member.memberId.toString(),
        },
      }));

    // Deduplicate members by DID to prevent duplicate entries
    const uniqueMembers = membersForVisibility.filter(
      (member, index, self) =>
        index === self.findIndex((m) => m.did === member.did),
    );

    return uniqueMembers;
  }

  /**
   * Check if we should show the visibility dialog
   * Returns true if there are members for visibility and either:
   * - This is the first time (no previous members tracked), OR
   * - New members have been added since last check (not removed), OR
   * - This is a manual refresh (isManualRefresh flag is set)
   */
  shouldShowVisibilityDialog(): boolean {
    // Only show for members who can see other members (i.e., they are in the decrypted members list)
    const currentUserMember = this.decryptedMembers.find(
      (member) => member.did === this.activeDid,
    );

    // If the current user is not in the decrypted members list, they can't see anyone
    if (!currentUserMember) {
      return false;
    }

    const currentMembers = this.getMembersForVisibility();

    if (currentMembers.length === 0) {
      return false;
    }

    // If no previous members tracked, show dialog
    if (this.previousVisibilityMembers.length === 0) {
      return true;
    }

    // If this is a manual refresh, always show dialog if there are members
    if (this.isManualRefresh) {
      return true;
    }

    // Check if new members have been added (not just any change)
    const currentMemberIds = currentMembers.map((m) => m.did);
    const previousMemberIds = this.previousVisibilityMembers;

    // Find new members (members in current but not in previous)
    const newMembers = currentMemberIds.filter(
      (id) => !previousMemberIds.includes(id),
    );

    // Only show dialog if there are new members added
    return newMembers.length > 0;
  }

  /**
   * Update the tracking of previous visibility members
   */
  updatePreviousVisibilityMembers() {
    const currentMembers = this.getMembersForVisibility();
    this.previousVisibilityMembers = currentMembers.map((m) => m.did);
  }

  /**
   * Check if we should show the admit pending members dialog
   */
  shouldShowAdmitPendingDialog(): boolean {
    // Don't show if already dismissed
    if (this.admitDialogDismissed) {
      return false;
    }

    // Only show for the organizer of the meeting
    if (!this.isOrganizer) {
      return false;
    }

    const pendingMembers = this.getPendingMembers();
    return pendingMembers.length > 0;
  }

  /**
   * Show the admit pending members dialog if conditions are met
   */
  checkAndShowAdmitPendingDialog() {
    if (this.shouldShowAdmitPendingDialog()) {
      this.showAdmitPendingDialogMethod();
    } else {
      // Ensure dialog state is false when no pending members
      this.showAdmitPendingDialog = false;
    }
  }

  /**
   * Show the visibility dialog if conditions are met
   */
  checkAndShowVisibilityDialog() {
    if (this.shouldShowVisibilityDialog()) {
      this.showSetBulkVisibilityDialog();
    }
    this.updatePreviousVisibilityMembers();
  }

  checkWhetherContactBeforeAdmitting(decrMember: DecryptedMember) {
    const contact = this.getContactFor(decrMember.did);
    if (!decrMember.member.admitted && !contact) {
      // If not a contact, show confirmation dialog
      this.$notify(
        {
          group: "modal",
          type: "confirm",
          title: NOTIFY_ADD_CONTACT_FIRST.title,
          text: NOTIFY_ADD_CONTACT_FIRST.text,
          yesText: NOTIFY_ADD_CONTACT_FIRST.yesText,
          noText: NOTIFY_ADD_CONTACT_FIRST.noText,
          onYes: async () => {
            await this.addAsContact(decrMember);
            // After adding as contact, proceed with admission
            await this.toggleAdmission(decrMember);
          },
          onNo: async () => {
            // If they choose not to add as contact, show second confirmation
            this.$notify(
              {
                group: "modal",
                type: "confirm",
                title: NOTIFY_CONTINUE_WITHOUT_ADDING.title,
                text: NOTIFY_CONTINUE_WITHOUT_ADDING.text,
                yesText: NOTIFY_CONTINUE_WITHOUT_ADDING.yesText,
                onYes: async () => {
                  await this.toggleAdmission(decrMember);
                },
                onCancel: async () => {
                  // Do nothing, effectively canceling the operation
                },
              },
              TIMEOUTS.MODAL,
            );
          },
        },
        TIMEOUTS.MODAL,
      );
    } else {
      // If already a contact, proceed directly with admission
      this.toggleAdmission(decrMember);
    }
  }

  async toggleAdmission(decrMember: DecryptedMember) {
    try {
      const headers = await getHeaders(this.activeDid);
      await this.axios.put(
        `${this.apiServer}/api/partner/groupOnboardMember/${decrMember.member.memberId}`,
        { admitted: !decrMember.member.admitted },
        { headers },
      );
      // Update local state
      decrMember.member.admitted = !decrMember.member.admitted;

      const oldContact = this.getContactFor(decrMember.did);
      // if admitted, now register that user if they are not registered
      if (
        decrMember.member.admitted &&
        !decrMember.isRegistered &&
        !oldContact?.registered
      ) {
        const contactOldOrNew: Contact = oldContact || {
          did: decrMember.did,
          name: decrMember.name,
        };
        try {
          const result = await register(
            this.activeDid,
            this.apiServer,
            this.axios,
            contactOldOrNew,
          );
          if (result.success) {
            decrMember.isRegistered = true;
            if (oldContact) {
              await this.$updateContact(decrMember.did, { registered: true });
              oldContact.registered = true;
            }
            this.notify.success(
              "Besides being admitted, they were also registered.",
              TIMEOUTS.STANDARD,
            );
          } else {
            throw result;
          }
          // eslint-disable-next-line @typescript-eslint/no-explicit-any
        } catch (error: any) {
          // registration failure is likely explained by a message from the server$notif
          const additionalInfo =
            serverMessageForUser(error) || error?.error || "";
          this.notify.warning(
            "They were admitted to the meeting. However, registration failed. You can register them from the contacts screen. " +
              additionalInfo,
            TIMEOUTS.VERY_LONG,
          );
        }
      }
    } catch (error) {
      this.$logAndConsole(
        "Error toggling admission: " + errorStringForLog(error),
        true,
      );
      this.emitError(
        serverMessageForUser(error) ||
          "Failed to update member admission status.",
      );
    }
  }

  async addAsContact(member: DecryptedMember) {
    try {
      const newContact = {
        did: member.did,
        name: member.name,
      };

      await this.$insertContact(newContact);
      this.contacts.push(newContact);

      this.notify.success(
        "They were added to your contacts.",
        TIMEOUTS.STANDARD,
      );
    } catch (err) {
      this.$logAndConsole(
        "Error adding contact: " + errorStringForLog(err),
        true,
      );
      let message = "An error prevented adding this contact.";
      if (err instanceof Error && err.message?.indexOf("already exists") > -1) {
        message = "This person is already in your contact list.";
      }
      this.notify.error(message, TIMEOUTS.LONG);
    }
  }

  showAdmitPendingDialogMethod() {
    // Filter members to show only pending (non-admitted) members
    const pendingMembers = this.getPendingMembers();

    // Only show dialog if there are pending members
    if (pendingMembers.length === 0) {
      this.showAdmitPendingDialog = false;
      return;
    }

    // Pause auto-refresh when dialog opens
    this.stopAutoRefresh();

    // Open the dialog directly
    this.pendingMembersData = pendingMembers;
    this.showAdmitPendingDialog = true;
  }

  showSetBulkVisibilityDialog() {
    // Filter members to show only those who need visibility set
    const membersForVisibility = this.getMembersForVisibility();

    // Pause auto-refresh when dialog opens
    this.stopAutoRefresh();

    // Open the dialog directly
    this.visibilityDialogMembers = membersForVisibility;
    this.showSetVisibilityDialog = true;

    // Reset manual refresh flag after dialog is shown
    this.isManualRefresh = false;
  }

  startAutoRefresh() {
    let lastRefreshTime = Date.now();
    this.countdownTimer = 10;

    this.autoRefreshInterval = setInterval(() => {
      const now = Date.now();
      const timeSinceLastRefresh = (now - lastRefreshTime) / 1000;

      if (timeSinceLastRefresh >= 10) {
        // Time to refresh
        this.refreshData();
        lastRefreshTime = now;
        this.countdownTimer = 10;
      } else {
        // Update countdown
        this.countdownTimer = Math.max(
          0,
          Math.round(10 - timeSinceLastRefresh),
        );
      }
    }, 1000); // Update every second
  }

  stopAutoRefresh() {
    if (this.autoRefreshInterval) {
      clearInterval(this.autoRefreshInterval);
      this.autoRefreshInterval = null;
    }
  }

  async manualRefresh() {
    // Clear existing auto-refresh interval
    if (this.autoRefreshInterval) {
      clearInterval(this.autoRefreshInterval);
      this.autoRefreshInterval = null;
    }

    // Set manual refresh flag
    this.isManualRefresh = true;
    // Reset the dismissed flag on manual refresh
    this.admitDialogDismissed = false;

    // Trigger immediate refresh
    await this.refreshData();

    // Only start auto-refresh if no dialogs are showing
    if (!this.showAdmitPendingDialog && !this.showSetVisibilityDialog) {
      this.startAutoRefresh();
    }
  }

  // Admit Pending Members Dialog methods
  async closeAdmitPendingDialog() {
    this.showAdmitPendingDialog = false;
    this.pendingMembersData = [];
    this.admitDialogDismissed = true;

    // Handle manual refresh flow
    if (this.isManualRefresh) {
      await this.handleManualRefreshFlow();
      this.isManualRefresh = false;
    } else {
      // Normal flow: refresh data and resume auto-refresh
      this.refreshData();
      this.startAutoRefresh();
    }
  }

  async handleManualRefreshFlow() {
    // Refresh data to reflect any changes made in the admit dialog
    await this.refreshData();

    // Use the same logic as normal flow to check for visibility dialog
    this.checkAndShowVisibilityDialog();

    // If no visibility dialog was shown, resume auto-refresh
    if (!this.showSetVisibilityDialog) {
      this.startAutoRefresh();
    }
  }

  async onAdmitPendingSuccess(_result: {
    admittedCount: number;
    contactAddedCount: number;
    visibilitySetCount: number;
  }) {
    // After admitting pending members, close the admit dialog
    // The visibility dialog will be handled by the closeAdmitPendingDialog flow
    await this.closeAdmitPendingDialog();
  }

  // Set Visibility Dialog methods
  closeSetVisibilityDialog() {
    this.showSetVisibilityDialog = false;
    this.visibilityDialogMembers = [];
    // Refresh data when dialog is closed to reflect any changes made
    this.refreshData();
    // Resume auto-refresh when dialog is closed
    this.startAutoRefresh();
  }

  beforeDestroy() {
    this.stopAutoRefresh();
  }
}
</script>

<style scoped>
/* Button Classes */
.btn-action-refresh {
  /* stylelint-disable-next-line at-rule-no-unknown */
  @apply w-8 h-8 flex items-center justify-center rounded-full 
    bg-blue-100 text-blue-600 hover:bg-blue-200 hover:text-blue-800 
    transition-colors;
}

.btn-add-contact {
  /* stylelint-disable-next-line at-rule-no-unknown */
  @apply text-lg text-green-600 hover:text-green-800 
    transition-colors;
}

.btn-info-contact,
.btn-info-admission {
  /* stylelint-disable-next-line at-rule-no-unknown */
  @apply text-slate-400 hover:text-slate-600 
    transition-colors;
}

.btn-admission-add {
  /* stylelint-disable-next-line at-rule-no-unknown */
  @apply text-lg text-blue-500 hover:text-blue-700 
    transition-colors;
}

.btn-admission-remove {
  /* stylelint-disable-next-line at-rule-no-unknown */
  @apply text-lg text-rose-500 hover:text-rose-700 
    transition-colors;
}
</style>
