<template>
  <router-view />

  <!-- Messages in the upper-right - https://github.com/emmanuelsw/notiwind -->
  <NotificationGroup group="alert">
    <div
      class="fixed z-[120] top-[max(1rem,env(safe-area-inset-top),var(--safe-area-inset-top,0px))] right-4 left-4 sm:left-auto sm:w-full sm:max-w-sm flex flex-col items-start justify-end"
    >
      <Notification
        v-slot="{ notifications, close }"
        enter="transform ease-out duration-300 transition"
        enter-from="translate-y-2 opacity-0 sm:translate-y-0 sm:translate-x-4"
        enter-to="translate-y-0 opacity-100 sm:translate-x-0"
        leave="transition ease-in duration-500"
        leave-from="opacity-100"
        leave-to="opacity-0"
        move="transition duration-500"
        move-delay="delay-300"
      >
        <div
          v-for="notification in notifications"
          :key="notification.id"
          class="w-full"
          role="alert"
        >
          <div
            v-if="notification.type === 'toast'"
            class="w-full max-w-sm mx-auto mb-3 overflow-hidden bg-slate-900/90 text-white rounded-lg shadow-md"
          >
            <div class="w-full px-4 py-3 overflow-hidden">
              <h4 class="font-semibold text-ellipsis overflow-hidden">
                {{ notification.title }}
              </h4>
              <p class="text-sm text-ellipsis overflow-hidden">
                {{ notification.text }}
              </p>
            </div>
          </div>

          <div
            v-if="notification.type === 'info'"
            class="flex w-full max-w-sm mx-auto mb-3 overflow-hidden bg-slate-100 rounded-lg shadow-md"
          >
            <div
              class="flex items-center justify-center w-12 bg-slate-600 text-slate-100"
            >
              <font-awesome
                icon="circle-info"
                class="fa-fw fa-xl"
              ></font-awesome>
            </div>

            <div
              class="relative w-full pl-4 pr-8 py-2 text-slate-900 overflow-hidden"
            >
              <h4 class="font-semibold text-ellipsis overflow-hidden">
                {{ notification.title }}
              </h4>
              <p class="text-sm text-ellipsis overflow-hidden">
                {{ notification.text }}
              </p>

              <button
                class="absolute top-2 right-2 px-0.5 py-0 rounded-full bg-slate-200 text-slate-600"
                @click="close(notification.id)"
              >
                <font-awesome icon="xmark" class="fa-fw"></font-awesome>
              </button>
            </div>
          </div>

          <div
            v-if="notification.type === 'success'"
            class="flex w-full max-w-sm mx-auto mb-3 overflow-hidden bg-emerald-100 rounded-lg shadow-md"
          >
            <div
              class="flex items-center justify-center w-12 bg-emerald-600 text-emerald-100"
            >
              <font-awesome
                icon="circle-info"
                class="fa-fw fa-xl"
              ></font-awesome>
            </div>

            <div
              class="relative w-full pl-4 pr-8 py-2 text-emerald-900 overflow-hidden"
            >
              <h4 class="font-semibold text-ellipsis overflow-hidden">
                {{ notification.title }}
              </h4>
              <p class="text-sm text-ellipsis overflow-hidden">
                {{ notification.text }}
              </p>

              <button
                class="absolute top-2 right-2 px-0.5 py-0 rounded-full bg-emerald-200 text-emerald-600"
                @click="close(notification.id)"
              >
                <font-awesome icon="xmark" class="fa-fw"></font-awesome>
              </button>
            </div>
          </div>

          <div
            v-if="notification.type === 'warning'"
            class="flex w-full max-w-sm mx-auto mb-3 overflow-hidden bg-amber-100 rounded-lg shadow-md"
          >
            <div
              class="flex items-center justify-center w-12 bg-amber-600 text-amber-100"
            >
              <font-awesome
                icon="triangle-exclamation"
                class="fa-fw fa-xl"
              ></font-awesome>
            </div>

            <div
              class="relative w-full pl-4 pr-8 py-2 text-amber-900 overflow-hidden"
            >
              <h4 class="font-semibold text-ellipsis overflow-hidden">
                {{ notification.title }}
              </h4>
              <p class="text-sm text-ellipsis overflow-hidden">
                {{ notification.text }}
              </p>

              <button
                class="absolute top-2 right-2 px-0.5 py-0 rounded-full bg-amber-200 text-amber-600"
                @click="close(notification.id)"
              >
                <font-awesome icon="xmark" class="fa-fw"></font-awesome>
              </button>
            </div>
          </div>

          <div
            v-if="notification.type === 'danger'"
            class="flex w-full max-w-sm mx-auto mb-3 overflow-hidden bg-rose-100 rounded-lg shadow-md"
          >
            <div
              class="flex items-center justify-center w-12 bg-rose-600 text-rose-100"
            >
              <font-awesome
                icon="triangle-exclamation"
                class="fa-fw fa-xl"
              ></font-awesome>
            </div>

            <div
              class="relative w-full pl-4 pr-8 py-2 text-rose-900 overflow-hidden"
            >
              <h4 class="font-semibold text-ellipsis overflow-hidden">
                {{ notification.title }}
              </h4>
              <p class="text-sm text-ellipsis overflow-hidden">
                {{ notification.text }}
              </p>

              <button
                class="absolute top-2 right-2 px-0.5 py-0 rounded-full bg-rose-200 text-rose-600"
                @click="close(notification.id)"
              >
                <font-awesome icon="xmark" class="fa-fw"></font-awesome>
              </button>
            </div>
          </div>
        </div>
      </Notification>
    </div>
  </NotificationGroup>

  <!--
    This "group" of "modal" is the prompt for an answer.
    Set "type" as follows: "confirm" for yes/no, and "notification" ones:
      "-permission", "-mute", "-off"
  -->
  <NotificationGroup group="modal">
    <div
      class="fixed z-[100] top-[max(env(safe-area-inset-top),var(--safe-area-inset-top,0px))] inset-x-0 w-full"
    >
      <Notification
        v-slot="{ notifications, close }"
        enter="transform ease-out duration-300 transition"
        enter-from="translate-y-2 opacity-0 sm:translate-y-4"
        enter-to="translate-y-0 opacity-100 sm:translate-y-0"
        leave="transition ease-in duration-500"
        leave-from="opacity-100"
        leave-to="opacity-0"
        move="transition duration-500"
        move-delay="delay-300"
      >
        <!-- see NotificationIface in constants/app.ts -->
        <div
          v-for="notification in notifications"
          :key="notification.id"
          class="w-full"
          role="alert"
        >
          <!--
            Type of "confirm" will post a message.
            With onYes function, show a "Yes" button to call that function.
            With onNo function, show a "No" button to call that function,
              and pass it state of "askAgain" field shown if you set promptToStopAsking.
          -->
          <div
            v-if="notification.type === 'confirm'"
            class="absolute inset-0 h-screen flex flex-col items-center justify-center bg-slate-900/50"
          >
            <div
              class="flex w-11/12 max-w-sm mx-auto mb-3 overflow-hidden bg-white rounded-lg shadow-lg"
            >
              <div class="w-full px-6 py-6 text-slate-900 text-center">
                <span class="font-semibold text-lg">
                  {{ notification.title }}
                </span>
                <p class="text-sm mb-2">{{ notification.text }}</p>

                <button
                  v-if="notification.onYes"
                  class="block w-full text-center text-md font-bold uppercase bg-blue-600 text-white px-2 py-2 rounded-md mb-2"
                  @click="
                    notification.onYes();
                    close(notification.id);
                  "
                >
                  Yes{{
                    notification.yesText ? ", " + notification.yesText : ""
                  }}
                </button>

                <button
                  v-if="notification.onNo"
                  class="block w-full text-center text-md font-bold uppercase bg-yellow-600 text-white px-2 py-2 rounded-md mb-2"
                  @click="
                    notification.onNo(stopAsking);
                    close(notification.id);
                    stopAsking = false; // reset value
                  "
                >
                  No{{ notification.noText ? ", " + notification.noText : "" }}
                </button>

                <label
                  v-if="notification.promptToStopAsking && notification.onNo"
                  for="toggleStopAsking"
                  class="flex items-center justify-between cursor-pointer my-4"
                  @click="stopAsking = !stopAsking"
                >
                  <!-- label -->
                  <span class="ml-2">... and do not ask again.</span>
                  <!-- toggle -->
                  <div class="relative ml-2">
                    <!-- input -->
                    <input
                      v-model="stopAsking"
                      type="checkbox"
                      name="stopAsking"
                      class="sr-only"
                    />
                    <!-- line -->
                    <div class="block bg-slate-500 w-14 h-8 rounded-full"></div>
                    <!-- dot -->
                    <div
                      class="dot absolute left-1 top-1 bg-slate-400 w-6 h-6 rounded-full transition"
                    ></div>
                  </div>
                </label>

                <button
                  class="block w-full text-center text-md font-bold uppercase bg-slate-600 text-white px-2 py-2 rounded-md"
                  @click="
                    notification.onCancel
                      ? notification.onCancel(stopAsking)
                      : null;
                    close(notification.id);
                    stopAsking = false; // reset value for next time they open this modal
                  "
                >
                  {{ notification.onYes ? "Cancel" : "Close" }}
                </button>
              </div>
            </div>
          </div>

          <div
            v-if="notification.type === 'notification-mute'"
            class="absolute inset-0 h-screen flex flex-col items-center justify-center bg-slate-900/50"
          >
            <div
              class="flex w-11/12 max-w-sm mx-auto mb-3 overflow-hidden bg-white rounded-lg shadow-lg"
            >
              <div class="w-full px-6 py-6 text-slate-900 text-center">
                <p class="text-lg mb-4">Mute app notifications:</p>

                <button
                  class="block w-full text-center text-md font-bold uppercase bg-blue-600 text-white px-2 py-2 rounded-md mb-2"
                >
                  For 1 Day
                </button>
                <button
                  class="block w-full text-center text-md font-bold uppercase bg-blue-600 text-white px-2 py-2 rounded-md mb-2"
                >
                  For 2 Days
                </button>
                <button
                  class="block w-full text-center text-md font-bold uppercase bg-blue-600 text-white px-2 py-2 rounded-md mb-2"
                >
                  For 1 Week
                </button>
                <button
                  class="block w-full text-center text-md font-bold uppercase bg-blue-600 text-white px-2 py-2 rounded-md mb-2"
                >
                  Until I turn it back on
                </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="close(notification.id)"
                >
                  Cancel
                </button>
              </div>
            </div>
          </div>

          <div
            v-if="notification.type === 'notification-off'"
            class="absolute inset-0 h-screen flex flex-col items-center justify-center bg-slate-900/50"
          >
            <div
              class="flex w-11/12 max-w-sm mx-auto mb-3 overflow-hidden bg-white rounded-lg shadow-lg"
            >
              <div class="w-full px-6 py-6 text-slate-900 text-center">
                <p class="text-lg mb-4">
                  Would you like to <b>turn off</b> this notification?
                </p>

                <button
                  class="block w-full text-center text-md font-bold uppercase bg-rose-600 text-white px-2 py-2 rounded-md mb-2"
                  @click="
                    close(notification.id);
                    turnOffNotifications(notification);
                  "
                >
                  Turn Off Notification
                </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="close(notification.id)"
                >
                  Leave it On
                </button>
              </div>
            </div>
          </div>

          <div
            v-if="notification.type === 'set-visibility-meeting-members'"
            class="absolute inset-0 h-screen flex flex-col items-center justify-center bg-slate-900/50"
          >
            <div
              class="flex w-11/12 max-w-lg mx-auto my-4 overflow-y-scroll bg-white rounded-lg shadow-lg"
            >
              <div class="w-full px-6 py-6 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(notification)"
                  class="mb-4"
                >
                  <table
                    class="w-full border-collapse border border-slate-300 text-sm text-start"
                  >
                    <thead
                      v-if="
                        notification.membersData &&
                        notification.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(notification)"
                              :indeterminate="isIndeterminate(notification)"
                              @change="toggleSelectAll(notification)"
                            />
                            Select All
                          </label>
                        </th>
                      </tr>
                    </thead>
                    <tbody>
                      <!-- Dynamic data from MembersList -->
                      <tr
                        v-if="
                          !notification.membersData ||
                          notification.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 notification.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="
                      notification.membersData &&
                      notification.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(notification);
                      closeDialog(notification, close);
                    "
                  >
                    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="closeDialog(notification, close)"
                  >
                    {{
                      notification.membersData &&
                      notification.membersData.length > 0
                        ? "Maybe Later"
                        : "Cancel"
                    }}
                  </button>
                </div>
              </div>
            </div>
          </div>
        </div>
      </Notification>
    </div>
  </NotificationGroup>
</template>

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

import { NotificationIface } from "./constants/app";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
import { logger } from "./utils/logger";
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { SOMEONE_UNNAMED } from "@/constants/entities";
import { setVisibilityUtil } from "./libs/endorserServer";

interface Settings {
  notifyingNewActivityTime?: string;
  notifyingReminderTime?: string;
}

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

  stopAsking = false;
  selectedMembers: string[] = [];
  selectionInitialized = false;

  get hasSelectedMembers() {
    return this.selectedMembers.length > 0;
  }
  activeDid = "";
  apiServer = "";

  async created() {
    // Initialize settings
    const settings = await this.$accountSettings();
    this.apiServer = settings.apiServer || "";

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

  isAllSelected(notification: NotificationIface) {
    const membersData = notification?.membersData || [];
    if (!membersData || membersData.length === 0) return false;
    return membersData.every((member) =>
      this.selectedMembers.includes(member.did),
    );
  }

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

  toggleSelectAll(notification: NotificationIface) {
    const membersData = notification?.membersData || [];
    if (!membersData || membersData.length === 0) return;

    if (this.isAllSelected(notification)) {
      // Deselect all
      this.selectedMembers = [];
    } else {
      // Select all
      this.selectedMembers = 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);
  }

  shouldInitializeSelection(notification: NotificationIface) {
    // This method will initialize selection when the dialog opens
    if (
      notification?.type === "set-visibility-meeting-members" &&
      !this.selectionInitialized
    ) {
      this.initializeSelection(notification);
      this.selectionInitialized = true;
    }
    return true;
  }

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

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

  async setVisibilityForSelectedMembers(notification: NotificationIface) {
    try {
      const membersData = notification?.membersData || [];
      const selectedMembers = 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,
      );
    } 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;
    }
  }

  async closeDialog(
    notification: NotificationIface,
    closeFn: (id: string) => void,
  ) {
    this.resetSelection();

    // Close the notification first
    closeFn(notification.id);

    // Then call the callback after a short delay to ensure dialog is closed
    setTimeout(async () => {
      if (notification.callback) {
        await notification.callback();
      }
    }, 100);
  }

  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,
    );
  }

  async turnOffNotifications(
    notification: NotificationIface,
  ): Promise<boolean> {
    let subscription: PushSubscriptionJSON | null = null;
    let allGoingOff = false;

    try {
      const settings: Settings = await this.$accountSettings();

      const notifyingNewActivity = !!settings?.notifyingNewActivityTime;
      const notifyingReminder = !!settings?.notifyingReminderTime;

      if (!notifyingNewActivity || !notifyingReminder) {
        allGoingOff = true;
      }

      await navigator.serviceWorker?.ready
        .then((registration) => {
          return registration.pushManager.getSubscription();
        })
        .then(async (subscript: PushSubscription | null) => {
          if (subscript) {
            subscription = subscript.toJSON();

            if (allGoingOff) {
              await subscript.unsubscribe();
            }
          } else {
            this.$logAndConsole("Subscription object is not available.");
          }
        })
        .catch((error) => {
          this.$logAndConsole(
            "Push provider server communication failed: " +
              JSON.stringify(error),
            true,
          );
          logger.error("Error during subscription fetch:", error);
        });

      if (!subscription) {
        this.$notify(
          {
            group: "alert",
            type: "info",
            title: "Finished",
            text: "Notifications are off.",
          },
          5000,
        );
        return true;
      }

      const serverSubscription = {
        ...(subscription as PushSubscriptionJSON),
        ...(allGoingOff ? {} : { notifyType: notification.title }),
      };

      const pushServerSuccess = await fetch("/web-push/unsubscribe", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(serverSubscription),
      })
        .then(async (response) => {
          if (!response.ok) {
            const errorBody = await response.text();
            this.$logAndConsole(
              `Push server failed: ${response.status} ${errorBody}`,
              true,
            );
            logger.error("Push server error response:", errorBody);
          }
          return response.ok;
        })
        .catch((error) => {
          this.$logAndConsole(
            "Push server communication failed: " + JSON.stringify(error),
            true,
          );
          logger.error("Error during server communication:", error);
          return false;
        });

      const message = pushServerSuccess
        ? "Notification is off."
        : "Notification is still on. Try to turn it off again.";

      this.$notify(
        {
          group: "alert",
          type: "info",
          title: "Finished",
          text: message,
        },
        5000,
      );

      if (notification.callback) {
        notification.callback(pushServerSuccess);
      }

      return pushServerSuccess;
    } catch (error) {
      this.$logAndConsole(
        "Error turning off notifications: " + JSON.stringify(error),
        true,
      );
      logger.error("Critical error in turnOffNotifications:", error);

      this.$notify(
        {
          group: "alert",
          type: "error",
          title: "Error",
          text: "Failed to turn off notifications. Please try again.",
        },
        5000,
      );

      return false;
    }
  }
}
</script>

<style>
#Content {
  padding-left: max(
    1.5rem,
    env(safe-area-inset-left),
    var(--safe-area-inset-left, 0px)
  );
  padding-right: max(
    1.5rem,
    env(safe-area-inset-right),
    var(--safe-area-inset-right, 0px)
  );
  padding-top: max(
    1.5rem,
    env(safe-area-inset-top),
    var(--safe-area-inset-top, 0px)
  );
  padding-bottom: max(
    1.5rem,
    env(safe-area-inset-bottom),
    var(--safe-area-inset-bottom, 0px)
  );
}

#QuickNav ~ #Content {
  padding-bottom: calc(
    max(env(safe-area-inset-bottom), var(--safe-area-inset-bottom, 0px)) +
      6.333rem
  );
}
</style>
