/** * Data Export Section Component * * Provides UI and functionality for
exporting user data and backing up identifier seeds. * Includes buttons for seed
backup and database export, with platform-specific download instructions. * *
@component * @displayName DataExportSection * @example * ```vue *
<DataExportSection :active-did="currentDid" />
* ``` */

<template>
  <div
    id="sectionDataExport"
    class="bg-slate-100 rounded-md overflow-hidden px-4 py-4 mt-8 mb-8"
  >
    <div class="mb-2 font-bold">Data Export</div>
    <router-link
      v-if="activeDid"
      :to="{ name: 'seed-backup' }"
      class="block w-full text-center text-md bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-2 rounded-md mb-2 mt-2"
    >
      Backup Identifier Seed
    </router-link>

    <button
      :class="computedStartDownloadLinkClassNames()"
      class="block w-full text-center text-md bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-2 rounded-md"
      @click="exportDatabase()"
    >
      Download Settings & Contacts
      <br />
      (excluding Identifier Data)
    </button>
    <a
      ref="downloadLink"
      :class="computedDownloadLinkClassNames()"
      class="block w-full text-center text-md bg-gradient-to-b from-green-500 to-green-800 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-2 rounded-md mb-6"
    >
      If no download happened yet, click again here to download now.
    </a>
    <div v-if="platformCapabilities.needsFileHandlingInstructions" class="mt-4">
      <p>
        After the download, you can save the file in your preferred storage
        location.
      </p>
      <ul>
        <li
          v-if="platformCapabilities.isIOS"
          class="list-disc list-outside ml-4"
        >
          On iOS: You will be prompted to choose a location to save your backup
          file.
        </li>
        <li
          v-if="platformCapabilities.isMobile && !platformCapabilities.isIOS"
          class="list-disc list-outside ml-4"
        >
          On Android: You will be prompted to choose a location to save your
          backup file.
        </li>
      </ul>
    </div>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from "vue-facing-decorator";
import { NotificationIface } from "../constants/app";
import { db } from "../db/index";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "../services/PlatformServiceFactory";
import {
  PlatformService,
  PlatformCapabilities,
} from "../services/PlatformService";

/**
 * @vue-component
 * Data Export Section Component
 * Handles database export and seed backup functionality with platform-specific behavior
 */
@Component
export default class DataExportSection extends Vue {
  /**
   * Notification function injected by Vue
   * Used to show success/error messages to the user
   */
  $notify!: (notification: NotificationIface, timeout?: number) => void;

  /**
   * Active DID (Decentralized Identifier) of the user
   * Controls visibility of seed backup option
   * @required
   */
  @Prop({ required: true }) readonly activeDid!: string;

  /**
   * URL for the database export download
   * Created and revoked dynamically during export process
   * Only used in web platform
   */
  downloadUrl = "";

  /**
   * Platform service instance for platform-specific operations
   */
  private platformService: PlatformService =
    PlatformServiceFactory.getInstance();

  /**
   * Platform capabilities for the current platform
   */
  private get platformCapabilities(): PlatformCapabilities {
    return this.platformService.getCapabilities();
  }

  /**
   * Lifecycle hook to clean up resources
   * Revokes object URL when component is unmounted (web platform only)
   */
  beforeUnmount() {
    if (this.downloadUrl && this.platformCapabilities.hasFileDownload) {
      URL.revokeObjectURL(this.downloadUrl);
    }
  }

  /**
   * Exports the database to a JSON file
   * Uses platform-specific methods for saving the exported data
   * Shows success/error notifications to user
   *
   * @throws {Error} If export fails
   * @emits {Notification} Success or error notification
   */
  public async exportDatabase() {
    try {
      const blob = await db.export({
        prettyJson: true,
        transform: (table, value, key) => {
          if (table === "contacts") {
            // Dexie inserts a number 0 when some are undefined, so we need to totally remove them.
            Object.keys(value).forEach(prop => {
              if (value[prop] === undefined) {
                delete value[prop];
              }
            });
          }
          return { value, key };
        },
      });
      const fileName = `${db.name}-backup.json`;

      if (this.platformCapabilities.hasFileDownload) {
        // Web platform: Use download link
        this.downloadUrl = URL.createObjectURL(blob);
        const downloadAnchor = this.$refs.downloadLink as HTMLAnchorElement;
        downloadAnchor.href = this.downloadUrl;
        downloadAnchor.download = fileName;
        downloadAnchor.click();
        setTimeout(() => URL.revokeObjectURL(this.downloadUrl), 1000);
      } else if (this.platformCapabilities.hasFileSystem) {
        // Native platform: Write to app directory
        const content = await blob.text();
        await this.platformService.writeAndShareFile(fileName, content);
      }

      this.$notify(
        {
          group: "alert",
          type: "success",
          title: "Export Successful",
          text: this.platformCapabilities.hasFileDownload
            ? "See your downloads directory for the backup. It is in the Dexie format."
            : "You should have been prompted to save your backup file.",
        },
        -1,
      );
    } catch (error) {
      logger.error("Export Error:", error);
      this.$notify(
        {
          group: "alert",
          type: "danger",
          title: "Export Error",
          text: "There was an error exporting the data.",
        },
        3000,
      );
    }
  }

  /**
   * Computes class names for the initial download button
   * @returns Object with 'hidden' class when download is in progress (web platform only)
   */
  public computedStartDownloadLinkClassNames() {
    return {
      hidden: this.downloadUrl && this.platformCapabilities.hasFileDownload,
    };
  }

  /**
   * Computes class names for the secondary download link
   * @returns Object with 'hidden' class when no download is available or not on web platform
   */
  public computedDownloadLinkClassNames() {
    return {
      hidden: !this.downloadUrl || !this.platformCapabilities.hasFileDownload,
    };
  }
}
</script>
