<template>
  <div v-if="visible" class="dialog-overlay">
    <div class="dialog">
      <div class="text-slate-900 text-center">
        <h3 class="text-lg font-semibold leading-[1.25] mb-2">
          Set Visibility to Meeting Members
        </h3>
        <p class="text-sm mb-4">
          Would you like to <b>make your activities visible</b> to the following
          members? (This will also add them as contacts if they aren't already.)
        </p>

        <!-- Custom table area - you can customize this -->
        <div v-if="shouldInitializeSelection" class="mb-4">
          <table
            class="w-full border-collapse border border-slate-300 text-sm text-start"
          >
            <thead v-if="membersData && membersData.length > 0">
              <tr class="bg-slate-100 font-medium">
                <th class="border border-slate-300 px-3 py-2">
                  <label class="flex items-center gap-2">
                    <input
                      type="checkbox"
                      :checked="isAllSelected"
                      :indeterminate="isIndeterminate"
                      @change="toggleSelectAll"
                    />
                    Select All
                  </label>
                </th>
              </tr>
            </thead>
            <tbody>
              <!-- Dynamic data from MembersList -->
              <tr v-if="!membersData || membersData.length === 0">
                <td
                  class="border border-slate-300 px-3 py-2 text-center italic text-gray-500"
                >
                  No members need visibility settings
                </td>
              </tr>
              <tr
                v-for="member in membersData || []"
                :key="member.member.memberId"
              >
                <td class="border border-slate-300 px-3 py-2">
                  <div class="flex items-center justify-between gap-2">
                    <label class="flex items-center gap-2">
                      <input
                        type="checkbox"
                        :checked="isMemberSelected(member.did)"
                        @change="toggleMemberSelection(member.did)"
                      />
                      {{ member.name || SOMEONE_UNNAMED }}
                    </label>

                    <!-- Friend indicator - only show if they are already a contact -->
                    <font-awesome
                      v-if="member.isContact"
                      icon="user-circle"
                      class="fa-fw ms-auto text-slate-400 cursor-pointer hover:text-slate-600"
                      @click="showContactInfo"
                    />
                  </div>
                </td>
              </tr>
            </tbody>
          </table>
        </div>

        <div class="space-y-2">
          <button
            v-if="membersData && membersData.length > 0"
            :disabled="!hasSelectedMembers"
            :class="[
              'block w-full text-center text-md font-bold uppercase px-2 py-2 rounded-md',
              hasSelectedMembers
                ? 'bg-blue-600 text-white cursor-pointer'
                : 'bg-slate-400 text-slate-200 cursor-not-allowed',
            ]"
            @click="setVisibilityForSelectedMembers"
          >
            Set Visibility
          </button>
          <button
            class="block w-full text-center text-md font-bold uppercase bg-slate-600 text-white px-2 py-2 rounded-md"
            @click="cancel"
          >
            {{
              membersData && membersData.length > 0 ? "Maybe Later" : "Cancel"
            }}
          </button>
        </div>
      </div>
    </div>
  </div>
</template>

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

import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
import { SOMEONE_UNNAMED } from "@/constants/entities";
import { setVisibilityUtil } from "@/libs/endorserServer";
import { createNotifyHelpers } from "@/utils/notify";

interface MemberData {
  did: string;
  name: string;
  isContact: boolean;
  member: {
    memberId: string;
  };
}

@Component({
  mixins: [PlatformServiceMixin],
})
export default class SetBulkVisibilityDialog extends Vue {
  @Prop({ default: false }) visible!: boolean;
  @Prop({ default: () => [] }) membersData!: MemberData[];
  @Prop({ default: "" }) activeDid!: string;
  @Prop({ default: "" }) apiServer!: string;

  // Vue notification system
  $notify!: (
    notification: { group: string; type: string; title: string; text: string },
    timeout?: number,
  ) => void;

  // Notification system
  notify!: ReturnType<typeof createNotifyHelpers>;

  // Component state
  selectedMembers: string[] = [];
  selectionInitialized = false;

  // Constants
  // In Vue templates, imported constants need to be explicitly made available to the template
  readonly SOMEONE_UNNAMED = SOMEONE_UNNAMED;

  get hasSelectedMembers() {
    return this.selectedMembers.length > 0;
  }

  get isAllSelected() {
    if (!this.membersData || this.membersData.length === 0) return false;
    return this.membersData.every((member) =>
      this.selectedMembers.includes(member.did),
    );
  }

  get isIndeterminate() {
    if (!this.membersData || this.membersData.length === 0) return false;
    const selectedCount = this.membersData.filter((member) =>
      this.selectedMembers.includes(member.did),
    ).length;
    return selectedCount > 0 && selectedCount < this.membersData.length;
  }

  get shouldInitializeSelection() {
    // This method will initialize selection when the dialog opens
    if (!this.selectionInitialized) {
      this.initializeSelection();
      this.selectionInitialized = true;
    }
    return true;
  }

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

  initializeSelection() {
    // Reset selection when dialog opens
    this.selectedMembers = [];
    // Select all by default
    this.selectedMembers = this.membersData.map((member) => member.did);
  }

  resetSelection() {
    this.selectedMembers = [];
    this.selectionInitialized = false;
  }

  toggleSelectAll() {
    if (!this.membersData || this.membersData.length === 0) return;

    if (this.isAllSelected) {
      // Deselect all
      this.selectedMembers = [];
    } else {
      // Select all
      this.selectedMembers = this.membersData.map((member) => member.did);
    }
  }

  toggleMemberSelection(memberDid: string) {
    const index = this.selectedMembers.indexOf(memberDid);
    if (index > -1) {
      this.selectedMembers.splice(index, 1);
    } else {
      this.selectedMembers.push(memberDid);
    }
  }

  isMemberSelected(memberDid: string) {
    return this.selectedMembers.includes(memberDid);
  }

  async setVisibilityForSelectedMembers() {
    try {
      const selectedMembers = this.membersData.filter((member) =>
        this.selectedMembers.includes(member.did),
      );
      const notSelectedMembers = this.membersData.filter((member) =>
        !this.selectedMembers.includes(member.did),
      );

      let successCount = 0;

      for (const member of selectedMembers) {
        try {
          // If they're not a contact yet, add them as a contact first
          if (!member.isContact) {
            await this.addAsContact(member);
          }

          // Set their seesMe to true
          await this.updateContactVisibility(member.did, true);

          successCount++;
        } catch (error) {
          // eslint-disable-next-line no-console
          console.error(`Error processing member ${member.did}:`, error);
          // Continue with other members even if one fails
        }
      }

      // Show success notification
      this.$notify(
        {
          group: "alert",
          type: "success",
          title: "Visibility Set Successfully",
          text: `Visibility set for ${successCount} member${successCount === 1 ? "" : "s"}.`,
        },
        5000,
      );

      // Emit success event
      this.$emit("close", { notSelectedMemberDids: notSelectedMembers.map((member) => member.did) });
      this.close();
    } catch (error) {
      // eslint-disable-next-line no-console
      console.error("Error setting visibility:", error);
      this.$notify(
        {
          group: "alert",
          type: "danger",
          title: "Error",
          text: "Failed to set visibility for some members. Please try again.",
        },
        5000,
      );
    }
  }

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

      await this.$insertContact(newContact);
    } catch (err) {
      // eslint-disable-next-line no-console
      console.error("Error adding contact:", err);
      if (err instanceof Error && err.message?.indexOf("already exists") > -1) {
        // Contact already exists, continue
      } else {
        throw err; // Re-throw if it's not a duplicate error
      }
    }
  }

  async updateContactVisibility(did: string, seesMe: boolean) {
    try {
      // Get the contact object
      const contact = await this.$getContact(did);
      if (!contact) {
        throw new Error(`Contact not found for DID: ${did}`);
      }

      // Use the proper API to set visibility on the server
      const result = await setVisibilityUtil(
        this.activeDid,
        this.apiServer,
        this.axios,
        contact,
        seesMe,
      );

      if (!result.success) {
        throw new Error(result.error || "Failed to set visibility");
      }
    } catch (err) {
      // eslint-disable-next-line no-console
      console.error("Error updating contact visibility:", err);
      throw err;
    }
  }

  showContactInfo() {
    this.$notify(
      {
        group: "alert",
        type: "info",
        title: "Contact Info",
        text: "This user is already your contact, but your activities are not visible to them yet.",
      },
      5000,
    );
  }

  close() {
    this.resetSelection();
    this.$emit("close", { notSelectedMemberDids: this.membersData.map((member) => member.did) });
  }

  cancel() {
    this.close();
  }
}
</script>
