<template>
  <QuickNav selected="Contacts" />
  <TopMessage />

  <section id="Content" class="p-6 pb-24 max-w-3xl mx-auto">
    <!-- Heading -->
    <h1 id="ViewHeading" class="text-4xl text-center font-light mb-8">
      Onboarding Meetings
    </h1>

    <!-- Loading State -->
    <div v-if="isLoading" class="flex justify-center items-center py-8">
      <font-awesome icon="spinner" class="fa-spin-pulse" />
    </div>

    <div v-else-if="attendingMeeting">
      <p>You are in this meeting.</p>
      <div
        class="p-4 bg-white rounded-lg shadow hover:shadow-md transition-shadow cursor-pointer"
        @click="promptPassword(attendingMeeting)"
      >
        <div class="flex justify-between items-center">
          <h2 class="text-xl font-medium">{{ attendingMeeting.name }}</h2>
          <button
            class="text-red-600 hover:text-red-700 p-2"
            title="Leave Meeting"
            @click.stop="leaveMeeting"
          >
            <font-awesome icon="right-from-bracket" />
          </button>
        </div>
      </div>
    </div>

    <!-- Meeting List -->
    <div v-else class="space-y-4">
      <div
        v-for="meeting in meetings"
        :key="meeting.groupId"
        class="p-4 bg-white rounded-lg shadow hover:shadow-md transition-shadow cursor-pointer"
        @click="promptPassword(meeting)"
      >
        <h2 class="text-xl font-medium">{{ meeting.name }}</h2>
      </div>

      <!-- Create Meeting Button for registered users with no meetings -->
      <div
        v-if="meetings.length === 0 && isRegistered"
        class="text-center py-8"
      >
        <p class="text-gray-500 mb-4">No onboarding meetings available</p>
        <button
          class="bg-gradient-to-b from-green-400 to-green-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-6 py-3 rounded-md hover:from-green-500 hover:to-green-800 transition-colors"
          @click="createMeeting"
        >
          <font-awesome icon="plus" class="mr-2" />
          Create Meeting
        </button>
      </div>

      <!-- No meetings message for unregistered users -->
      <p
        v-if="meetings.length === 0 && !isRegistered"
        class="text-center text-gray-500 py-8"
      >
        No onboarding meetings available
      </p>
    </div>

    <!-- Password Dialog -->
    <div
      v-if="showPasswordDialog"
      class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4"
    >
      <div class="bg-white rounded-lg p-6 max-w-sm w-full">
        <h3 class="text-lg font-medium mb-4">Enter Meeting Password</h3>
        <input
          ref="passwordInput"
          v-model="password"
          type="text"
          class="w-full px-3 py-2 border rounded-md mb-4"
          placeholder="Enter password"
          @keyup.enter="submitPassword"
        />
        <div class="flex justify-end space-x-4">
          <button
            class="px-4 py-2 bg-gray-200 rounded hover:bg-gray-300"
            @click="cancelPasswordDialog"
          >
            Cancel
          </button>
          <button
            class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
            @click="submitPassword"
          >
            Submit
          </button>
        </div>
      </div>
    </div>
  </section>
</template>

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

import QuickNav from "../components/QuickNav.vue";
import TopMessage from "../components/TopMessage.vue";
import { encryptMessage } from "../libs/crypto";
import {
  errorStringForLog,
  getHeaders,
  serverMessageForUser,
} from "../libs/endorserServer";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
import { NotificationIface } from "@/constants/app";

interface Meeting {
  name: string;
  groupId: number;
}

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

  notify!: ReturnType<typeof createNotifyHelpers>;

  activeDid = "";
  apiServer = "";
  attendingMeeting: Meeting | null = null;
  firstName = "";
  isLoading = false;
  isRegistered = false;
  meetings: Meeting[] = [];
  password = "";
  selectedMeeting: Meeting | null = null;
  showPasswordDialog = false;

  /**
   * Vue lifecycle hook - component initialization
   *
   * Initializes the component by loading user settings and fetching available
   * onboarding meetings. This method is called when the component is created
   * and sets up all necessary data for the meeting list interface.
   *
   * Workflow:
   * 1. Initialize notification system using createNotifyHelpers
   * 2. Load user account settings (DID, API server, registration status)
   * 3. Fetch available onboarding meetings from the server
   *
   * Dependencies:
   * - PlatformServiceMixin for settings access ($accountSettings)
   * - Server API for meeting data (fetchMeetings)
   *
   * Error Handling:
   * - Server errors during meeting fetch are handled in fetchMeetings()
   *
   * @author Matthew Raymer
   */
  async created() {
    this.notify = createNotifyHelpers(this.$notify);

    // Load user account settings
    const settings = await this.$accountSettings();

    // Use new Active Identity façade instead of settings.activeDid
    this.activeDid = (await this.$getActiveDid()) || "";
    this.apiServer = settings?.apiServer || "";
    this.firstName = settings?.firstName || "";
    this.isRegistered = !!settings?.isRegistered;

    await this.fetchMeetings();
  }

  /**
   * Fetches available onboarding meetings from the server
   *
   * This method retrieves the list of onboarding meetings that the user can join.
   * It first checks if the user is already attending a meeting, and if so,
   * displays that meeting instead of the full list.
   *
   * Workflow:
   * 1. Check if user is already attending a meeting (groupOnboardMember endpoint)
   * 2. If attending: Fetch meeting details and display single meeting view
   * 3. If not attending: Fetch all available meetings (groupsOnboarding endpoint)
   * 4. Handle loading states and error conditions
   *
   * API Endpoints Used:
   * - GET /api/partner/groupOnboardMember - Check current attendance
   * - GET /api/partner/groupOnboard/{id} - Get meeting details
   * - GET /api/partner/groupsOnboarding - Get all available meetings
   *
   * State Management:
   * - Sets isLoading flag during API calls
   * - Updates attendingMeeting or meetings array
   * - Handles error states with user notifications
   *
   * @author Matthew Raymer
   */
  async fetchMeetings() {
    this.isLoading = true;
    try {
      const headers = await getHeaders(this.activeDid);

      const response = await this.axios.get(
        this.apiServer + "/api/partner/groupOnboardMember",
        { headers },
      );

      if (response.data?.data) {
        const attendingMeetingId = response.data.data.groupId;

        const headers2 = await getHeaders(this.activeDid);
        const response2 = await this.axios.get(
          this.apiServer + "/api/partner/groupOnboard/" + attendingMeetingId,
          { headers: headers2 },
        );

        if (response2.data?.data) {
          this.attendingMeeting = response2.data.data;
          return;
        } else {
          this.$logAndConsole(
            "Error fetching meeting for user after saying they are in one.",
            true,
          );
        }
      } else {
        this.$logAndConsole(
          "Error fetching meeting for user after saying they are in one.",
          true,
        );
      }

      const headers2 = await getHeaders(this.activeDid);
      const response2 = await this.axios.get(
        this.apiServer + "/api/partner/groupsOnboarding",
        { headers: headers2 },
      );

      if (response2.data?.data) {
        this.meetings = response2.data.data;
      }
    } catch (error: unknown) {
      this.$logAndConsole(
        "Error fetching meetings: " + errorStringForLog(error),
        true,
      );
      this.notify.error(
        serverMessageForUser(error) || "There was a problem fetching meetings.",
        TIMEOUTS.LONG,
      );
    } finally {
      this.isLoading = false;
    }
  }

  /**
   * Opens the password dialog for joining a meeting
   *
   * This method initiates the process of joining an onboarding meeting by
   * opening a modal dialog that prompts the user for the meeting password.
   * The dialog is focused and ready for input when displayed.
   *
   * Workflow:
   * 1. Clear any previous password input
   * 2. Store the selected meeting for later use
   * 3. Show the password dialog modal
   * 4. Focus the password input field for immediate typing
   *
   * UI State Changes:
   * - Sets showPasswordDialog to true (shows modal)
   * - Clears password field for fresh input
   * - Stores selectedMeeting for password submission
   *
   * @param meeting - The meeting object the user wants to join
   * @author Matthew Raymer
   */
  promptPassword(meeting: Meeting) {
    this.password = "";
    this.selectedMeeting = meeting;
    this.showPasswordDialog = true;
    nextTick(() => {
      const input = this.$refs.passwordInput as HTMLInputElement;
      if (input) {
        input.focus();
      }
    });
  }

  /**
   * Cancels the password dialog and resets state
   *
   * This method handles the cancellation of the meeting password dialog.
   * It cleans up the dialog state and resets all related variables to
   * their initial state, ensuring a clean slate for future dialog interactions.
   *
   * State Cleanup:
   * - Clears password input field
   * - Removes selected meeting reference
   * - Hides password dialog modal
   *
   * This ensures that if the user reopens the dialog, they start with
   * a fresh state without any leftover data from previous attempts.
   *
   * @author Matthew Raymer
   */
  cancelPasswordDialog() {
    this.password = "";
    this.selectedMeeting = null;
    this.showPasswordDialog = false;
  }

  /**
   * Submits the password and joins the selected meeting
   *
   * This method handles the complete workflow of joining an onboarding meeting.
   * It encrypts the user's member data with the provided password and sends
   * it to the server to register the user as a meeting participant.
   *
   * Workflow:
   * 1. Validate that a meeting is selected (safety check)
   * 2. Create member data object with user information
   * 3. Encrypt member data using the meeting password
   * 4. Send encrypted data to server via groupOnboardMember endpoint
   * 5. On success: Navigate to meeting members view with credentials
   * 6. On failure: Show error notification to user
   *
   * Data Encryption:
   * - Member data includes: name, DID, registration status
   * - Data is encrypted using the meeting password for security
   * - Encrypted data is sent to server for verification
   *
   * Navigation:
   * - On successful join: Redirects to onboard-meeting-members view
   * - Passes groupId, password, and memberId as route parameters
   * - Allows user to see other meeting participants
   *
   * Error Handling:
   * - Invalid passwords result in server rejection
   * - Network errors are caught and displayed to user
   * - All errors are logged for debugging purposes
   *
   * @author Matthew Raymer
   */
  async submitPassword() {
    if (!this.selectedMeeting) {
      // this should never happen
      this.$logAndConsole(
        "No meeting selected when prompting for password, which should never happen.",
        true,
      );
      return;
    }

    try {
      // Create member data object
      const memberData = {
        name: this.firstName,
        did: this.activeDid,
        isRegistered: this.isRegistered,
      };
      const memberDataString = JSON.stringify(memberData);
      const encryptedMemberData = await encryptMessage(
        memberDataString,
        this.password,
      );

      // Get headers for authentication
      const headers = await getHeaders(this.activeDid);

      // Encrypt the member data
      const postResult = await this.axios.post(
        this.apiServer + "/api/partner/groupOnboardMember",
        {
          groupId: this.selectedMeeting.groupId,
          content: encryptedMemberData,
        },
        { headers },
      );

      if (postResult.data && postResult.data.success) {
        // Navigate to members view with password and groupId
        this.$router.push({
          name: "onboard-meeting-members",
          params: {
            groupId: this.selectedMeeting.groupId.toString(),
          },
          query: {
            password: this.password,
            memberId: postResult.data.memberId,
          },
        });

        this.cancelPasswordDialog();
      } else {
        throw { response: postResult };
      }
    } catch (error) {
      this.$logAndConsole(
        "Error joining meeting: " + errorStringForLog(error),
        true,
      );
      this.notify.error(
        serverMessageForUser(error) ||
          "There was a problem joining the meeting.",
        TIMEOUTS.LONG,
      );
    }
  }

  /**
   * Prompts user to confirm leaving the current meeting
   *
   * This method initiates the process of leaving an onboarding meeting.
   * It shows a confirmation dialog to prevent accidental departures,
   * then handles the server-side removal and UI updates.
   *
   * Workflow:
   * 1. Display confirmation dialog asking user to confirm departure
   * 2. On confirmation: Send DELETE request to groupOnboardMember endpoint
   * 3. On success: Clear attending meeting state and refresh meeting list
   * 4. Show success notification to user
   * 5. On failure: Show error notification with details
   *
   * Server Interaction:
   * - DELETE /api/partner/groupOnboardMember - Removes user from meeting
   * - Requires authentication headers for user verification
   * - Server handles the actual removal from meeting database
   *
   * State Management:
   * - Clears attendingMeeting when successfully left
   * - Refreshes meetings list to show updated availability
   * - Updates UI to show meeting list instead of single meeting
   *
   * User Experience:
   * - Confirmation prevents accidental departures
   * - Clear feedback on success/failure
   * - Seamless transition back to meeting list
   *
   * @author Matthew Raymer
   */
  async leaveMeeting() {
    this.notify.confirm(
      "Are you sure you want to leave this meeting?",
      async () => {
        try {
          const headers = await getHeaders(this.activeDid);
          await this.axios.delete(
            this.apiServer + "/api/partner/groupOnboardMember",
            { headers },
          );

          this.attendingMeeting = null;
          await this.fetchMeetings();

          this.notify.success("You left the meeting.", TIMEOUTS.LONG);
        } catch (error) {
          this.$logAndConsole(
            "Error leaving meeting: " + errorStringForLog(error),
            true,
          );
          this.notify.error(
            serverMessageForUser(error) ||
              "There was a problem leaving the meeting.",
            TIMEOUTS.LONG,
          );
        }
      },
    );
  }

  /**
   * Navigates to the meeting creation page
   *
   * This method handles the navigation to the meeting setup page where
   * registered users can create new onboarding meetings. It's only
   * available to users who are registered in the system.
   *
   * Navigation:
   * - Routes to onboard-meeting-setup view
   * - Allows user to configure new meeting settings
   * - Only accessible to registered users (controlled by template)
   *
   * User Flow:
   * - User clicks "Create Meeting" button
   * - System navigates to setup page
   * - User can configure meeting name, password, etc.
   * - New meeting becomes available to other users
   *
   * @author Matthew Raymer
   */
  createMeeting() {
    this.$router.push({ name: "onboard-meeting-setup" });
  }
}
</script>
