/** * Backup Files List Component * * Displays a list of backup files saved by
the app and provides options to: * - View backup files by type (contacts, seed,
other) * - Open individual files in the device's file viewer * - Access the
backup directory in the device's file explorer * * @component * @displayName
BackupFilesList * @example * ```vue *
<BackupFilesList />
* ``` */

<template>
  <div class="backup-files-list">
    <div class="flex justify-between items-center mb-4">
      <h3 class="text-lg font-semibold">Backup Files</h3>
      <div class="flex gap-2">
        <button
          v-if="platformCapabilities.hasFileSystem"
          class="text-sm bg-blue-500 hover:bg-blue-600 text-white px-3 py-1 rounded"
          :disabled="isLoading"
          @click="refreshFiles()"
        >
          <font-awesome
            icon="refresh"
            class="fa-fw"
            :class="{ 'animate-spin': isLoading }"
          />
          Refresh
        </button>
        <button
          v-if="platformCapabilities.hasFileSystem"
          class="text-sm bg-green-500 hover:bg-green-600 text-white px-3 py-1 rounded"
          :disabled="isLoading"
          @click="openBackupDirectory()"
        >
          <font-awesome icon="folder-open" class="fa-fw" />
          Open Directory
        </button>
        <button
          v-if="platformCapabilities.hasFileSystem && isDevelopment"
          class="text-sm bg-yellow-500 hover:bg-yellow-600 text-white px-3 py-1 rounded"
          :disabled="isLoading"
          title="Debug file discovery (development only)"
          @click="debugFileDiscovery()"
        >
          <font-awesome icon="bug" class="fa-fw" />
          Debug
        </button>
        <button
          :disabled="isLoading"
          class="px-3 py-1 bg-green-500 text-white rounded text-sm hover:bg-green-600 disabled:opacity-50"
          @click="createTestBackup"
        >
          Create Test Backup
        </button>
        <button
          :disabled="isLoading"
          class="px-3 py-1 bg-purple-500 text-white rounded text-sm hover:bg-purple-600 disabled:opacity-50"
          @click="testDirectoryContexts"
        >
          Test Contexts
        </button>
      </div>
    </div>

    <div v-if="isLoading" class="text-center py-4">
      <font-awesome icon="spinner" class="animate-spin fa-2x" />
      <p class="mt-2">Loading backup files...</p>
    </div>

    <div
      v-else-if="backupFiles.length === 0"
      class="text-center py-4 text-gray-500"
    >
      <font-awesome icon="folder-open" class="fa-2x mb-2" />
      <p>No backup files found</p>
      <p class="text-sm mt-1">
        Create backups using the export functions above
      </p>
      <div
        class="mt-3 p-3 bg-blue-50 border border-blue-200 rounded-lg text-left"
      >
        <p class="text-sm font-medium text-blue-800 mb-2">
          💡 How to create backup files:
        </p>
        <ul class="text-xs text-blue-700 space-y-1">
          <li>
            • Use the "Export Contacts" button above to create contact backups
          </li>
          <li>• Use the "Export Seed" button to backup your recovery phrase</li>
          <li>
            • Backup files are saved to persistent storage that survives app
            installations
          </li>
          <li
            v-if="platformCapabilities.isMobile && !platformCapabilities.isIOS"
            class="text-orange-700"
          >
            • On Android: Files are saved to Downloads/TimeSafari or app data
            directory
          </li>
          <li v-if="platformCapabilities.isIOS" class="text-orange-700">
            • On iOS: Files are saved to Documents folder (accessible via Files
            app)
          </li>
        </ul>
      </div>
    </div>

    <div v-else class="space-y-2">
      <!-- File Type Filter -->
      <div class="flex gap-2 mb-3">
        <button
          v-for="type in ['all', 'contacts', 'seed', 'other'] as const"
          :key="type"
          :class="[
            'text-sm px-3 py-1 rounded border',
            selectedType === type
              ? 'bg-blue-500 text-white border-blue-500'
              : 'bg-white text-gray-700 border-gray-300 hover:bg-gray-50',
          ]"
          @click="selectedType = type"
        >
          {{
            type === "all"
              ? "All"
              : type.charAt(0).toUpperCase() + type.slice(1)
          }}
          <span class="ml-1 text-xs"> ({{ getFileCountByType(type) }}) </span>
        </button>
      </div>

      <!-- Files List -->
      <div class="flex items-center gap-2 mb-2">
        <span v-for="(crumb, idx) in breadcrumbs" :key="idx">
          <span
            v-if="idx < breadcrumbs.length - 1"
            class="text-blue-600 cursor-pointer underline"
            @click="goToBreadcrumb(idx)"
          >
            {{ crumb }}
          </span>
          <span v-else class="font-bold">{{ crumb }}</span>
          <span v-if="idx < breadcrumbs.length - 1"> / </span>
        </span>
      </div>
      <div v-if="currentPath.length > 1" class="mb-2">
        <button class="text-xs text-blue-500 underline" @click="goUp">
          ⬅ Up
        </button>
      </div>
      <div class="mb-2">
        <label class="inline-flex items-center">
          <input
            v-model="debugShowAll"
            type="checkbox"
            class="mr-2"
            @change="loadDirectory"
          />
          <span class="text-xs">Debug: Show all entries as files</span>
        </label>
        <span v-if="debugShowAll" class="text-xs text-red-600 ml-2"
          >[Debug mode: forcibly treating all entries as files]</span
        >
      </div>
      <div class="space-y-2 max-h-64 overflow-y-auto">
        <div
          v-for="entry in folders"
          :key="'folder-' + entry.path"
          class="flex items-center justify-between p-3 bg-white border border-gray-200 rounded-lg hover:bg-gray-50 cursor-pointer"
          @click="openFolder(entry)"
        >
          <div class="flex items-center gap-2">
            <font-awesome icon="folder" class="fa-fw text-yellow-500" />
            <span class="font-medium">{{ entry.name }}</span>
            <span
              class="text-xs bg-gray-200 text-gray-700 px-2 py-0.5 rounded-full ml-2"
              >Folder</span
            >
          </div>
        </div>
        <div
          v-for="entry in files"
          :key="'file-' + entry.path"
          class="flex items-center justify-between p-3 bg-white border border-gray-200 rounded-lg hover:bg-gray-50"
        >
          <div class="flex-1 min-w-0">
            <div class="flex items-center gap-2">
              <font-awesome icon="file-alt" class="fa-fw text-gray-500" />
              <span class="font-medium truncate">{{ entry.name }}</span>
            </div>
            <div class="text-sm text-gray-500 mt-1">
              <span v-if="entry.size">{{ formatFileSize(entry.size) }}</span>
              <span v-else>Size unknown</span>
              <span
                v-if="entry.path && !platformCapabilities.isIOS"
                class="ml-2 text-xs text-blue-600"
                >📁 {{ entry.path }}</span
              >
            </div>
          </div>
          <div class="flex gap-2 ml-3">
            <button
              class="text-blue-500 hover:text-blue-700 p-1"
              title="Open file"
              @click="openFile(entry.uri, entry.name)"
            >
              <font-awesome icon="external-link-alt" class="fa-fw" />
            </button>
          </div>
        </div>
      </div>

      <!-- Summary -->
      <div class="text-sm text-gray-500 mt-3 pt-3 border-t">
        Showing {{ filteredFiles.length }} of {{ backupFiles.length }} backup
        files
      </div>

      <div class="text-sm text-gray-600 mb-2">
        <p>
          📁 Backup files are saved to persistent storage that survives app
          installations:
        </p>
        <ul class="list-disc list-inside ml-2 mt-1 text-xs">
          <li v-if="platformCapabilities.isIOS">
            iOS: Documents folder (accessible via Files app)
          </li>
          <li
            v-if="platformCapabilities.isMobile && !platformCapabilities.isIOS"
          >
            Android: Downloads/TimeSafari or external storage (accessible via
            file managers)
          </li>
          <li v-if="!platformCapabilities.isMobile">
            Desktop: User's download directory
          </li>
        </ul>
      </div>
    </div>
  </div>
</template>

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

/**
 * @vue-component
 * Backup Files List Component
 * Displays and manages backup files with platform-specific functionality
 */
@Component
export default class BackupFilesList extends Vue {
  /**
   * Notification function injected by Vue
   * Used to show success/error messages to the user
   */
  $notify!: (notification: NotificationIface, timeout?: number) => void;

  /**
   * 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();
  }

  /**
   * List of backup files found on the device
   */
  backupFiles: Array<{
    name: string;
    uri: string;
    size?: number;
    type: "contacts" | "seed" | "other";
    path?: string;
  }> = [];

  /**
   * Currently selected file type filter
   */
  selectedType: "all" | "contacts" | "seed" | "other" = "all";

  /**
   * Loading state for file operations
   */
  isLoading = false;

  /**
   * Interval for periodic refresh (5 minutes)
   */
  private refreshInterval: number | null = null;

  /**
   * Current path for folder navigation (array for breadcrumbs)
   */
  currentPath: string[] = [];

  /**
   * List of files/folders in the current directory
   */
  directoryEntries: Array<{
    name: string;
    uri: string;
    size?: number;
    path: string;
    type: "file" | "folder";
  }> = [];

  /**
   * Temporary debug mode to show all entries as files
   */
  debugShowAll = false;

  /**
   * Checks and requests storage permissions if needed.
   * Returns true if permission is granted, false otherwise.
   */
  private async ensureStoragePermission(): Promise<boolean> {
    logger.log(
      "[BackupFilesList] ensureStoragePermission called. platformCapabilities:",
      this.platformCapabilities,
    );
    if (!this.platformCapabilities.hasFileSystem) return true;
    // Only relevant for native platforms (Android/iOS)
    const platformService = this.platformService as any;
    if (typeof platformService.checkStoragePermissions === "function") {
      try {
        await platformService.checkStoragePermissions();
        logger.log("[BackupFilesList] Storage permission granted.");
        return true;
      } catch (error) {
        logger.error("[BackupFilesList] Storage permission denied:", error);

        // Get specific guidance for the platform
        let guidance =
          "This app needs permission to access your files to list and restore backups.";
        if (
          typeof platformService.getStoragePermissionGuidance === "function"
        ) {
          try {
            guidance = await platformService.getStoragePermissionGuidance();
          } catch (guidanceError) {
            logger.warn(
              "[BackupFilesList] Could not get permission guidance:",
              guidanceError,
            );
          }
        }

        this.$notify(
          {
            group: "alert",
            type: "warning",
            title: "Storage Permission Required",
            text: guidance,
          },
          10000, // Show for 10 seconds to give user time to read
        );
        return false;
      }
    }
    return true;
  }

  /**
   * Lifecycle hook to load backup files when component is mounted
   */
  async mounted() {
    logger.log(
      "[BackupFilesList] mounted hook called. platformCapabilities:",
      this.platformCapabilities,
    );
    if (this.platformCapabilities.hasFileSystem) {
      // Check/request permission before loading
      const hasPermission = await this.ensureStoragePermission();
      if (hasPermission) {
        // Set default root path
        if (this.platformCapabilities.isIOS) {
          this.currentPath = ["."];
        } else {
          this.currentPath = ["Download", "TimeSafari"];
        }
        await this.loadDirectory();
        this.refreshInterval = window.setInterval(
          () => {
            this.loadDirectory();
          },
          5 * 60 * 1000,
        );
      }
    }
  }

  /**
   * Lifecycle hook to clean up resources when component is unmounted
   */
  beforeUnmount() {
    if (this.refreshInterval) {
      clearInterval(this.refreshInterval);
      this.refreshInterval = null;
    }
  }

  /**
   * Computed property for filtered files based on selected type
   * Note: The 'All' tab count is sometimes too small. Logging for debugging.
   */
  get filteredFiles() {
    if (this.selectedType === "all") {
      logger.log("[BackupFilesList] filteredFiles (All):", this.backupFiles);
      return this.backupFiles;
    }
    const filtered = this.backupFiles.filter(
      (file) => file.type === this.selectedType,
    );
    logger.log(
      `[BackupFilesList] filteredFiles (${this.selectedType}):`,
      filtered,
    );
    return filtered;
  }

  /**
   * Computed property to check if we're in development mode
   */
  get isDevelopment(): boolean {
    return import.meta.env.DEV;
  }

  /**
   * Load the current directory entries
   */
  async loadDirectory() {
    if (!this.platformCapabilities.hasFileSystem) return;
    this.isLoading = true;
    try {
      const path =
        this.currentPath.join("/") ||
        (this.platformCapabilities.isIOS ? "." : "Download/TimeSafari");
      this.directoryEntries = await (
        this.platformService as PlatformService
      ).listFilesInDirectory(path, this.debugShowAll);
      logger.log("[BackupFilesList] Loaded directory:", {
        path,
        entries: this.directoryEntries,
      });
    } catch (error) {
      logger.error("[BackupFilesList] Failed to load directory:", error);
      this.directoryEntries = [];
    } finally {
      this.isLoading = false;
    }
  }

  /**
   * Navigate into a folder
   */
  async openFolder(entry: { name: string; path: string }) {
    this.currentPath.push(entry.name);
    await this.loadDirectory();
  }

  /**
   * Navigate to a breadcrumb
   */
  async goToBreadcrumb(index: number) {
    this.currentPath = this.currentPath.slice(0, index + 1);
    await this.loadDirectory();
  }

  /**
   * Go up one directory
   */
  async goUp() {
    if (this.currentPath.length > 1) {
      this.currentPath.pop();
      await this.loadDirectory();
    }
  }

  /**
   * Computed property for breadcrumbs
   */
  get breadcrumbs() {
    return this.currentPath;
  }

  /**
   * Computed property for showing files and folders
   */
  get folders() {
    return this.directoryEntries.filter((e) => e.type === "folder");
  }
  get files() {
    return this.directoryEntries.filter((e) => e.type === "file");
  }

  /**
   * Refreshes the list of backup files from the device
   */
  async refreshFiles() {
    logger.log("[BackupFilesList] refreshFiles called.");
    if (!this.platformCapabilities.hasFileSystem) {
      return;
    }
    // Check/request permission before refreshing
    const hasPermission = await this.ensureStoragePermission();
    if (!hasPermission) {
      this.backupFiles = [];
      this.isLoading = false;
      return;
    }
    this.isLoading = true;
    try {
      this.backupFiles = await this.platformService.listBackupFiles();
      logger.log("[BackupFilesList] Refreshed backup files:", {
        count: this.backupFiles.length,
        files: this.backupFiles.map((f) => ({
          name: f.name,
          type: f.type,
          path: f.path,
          size: f.size,
        })),
        platform: this.platformCapabilities.isIOS ? "iOS" : "Android",
        timestamp: new Date().toISOString(),
      });
      // Debug: Log file type distribution
      const typeCounts = {
        contacts: this.backupFiles.filter((f) => f.type === "contacts").length,
        seed: this.backupFiles.filter((f) => f.type === "seed").length,
        other: this.backupFiles.filter((f) => f.type === "other").length,
        total: this.backupFiles.length,
      };
      logger.log("[BackupFilesList] File type distribution:", typeCounts);
      // Log the full backupFiles array for debugging the 'All' tab count
      logger.log(
        "[BackupFilesList] backupFiles array for All tab:",
        this.backupFiles,
      );
    } catch (error) {
      logger.error("[BackupFilesList] Failed to refresh backup files:", error);
      this.$notify(
        {
          group: "alert",
          type: "danger",
          title: "Error Loading Files",
          text: "Failed to load backup files from your device.",
        },
        5000,
      );
    } finally {
      this.isLoading = false;
    }
  }

  /**
   * Creates a test backup file for debugging purposes
   */
  async createTestBackup() {
    try {
      this.isLoading = true;
      logger.log("[BackupFilesList] Creating test backup file");

      const result = await this.platformService.createTestBackupFile();

      if (result.success) {
        logger.log("[BackupFilesList] Test backup file created successfully:", {
          fileName: result.fileName,
          uri: result.uri,
          timestamp: new Date().toISOString(),
        });

        this.$notify(
          {
            group: "alert",
            type: "success",
            title: "Test Backup Created",
            text: `Test backup file "${result.fileName}" created successfully. Refresh the list to see it.`,
          },
          5000,
        );

        // Refresh the file list to show the new test file
        await this.refreshFiles();
      } else {
        throw new Error(result.error || "Failed to create test backup file");
      }
    } catch (error) {
      logger.error(
        "[BackupFilesList] Failed to create test backup file:",
        error,
      );
      this.$notify(
        {
          group: "alert",
          type: "danger",
          title: "Test Backup Failed",
          text: "Failed to create test backup file. Check the console for details.",
        },
        5000,
      );
    } finally {
      this.isLoading = false;
    }
  }

  /**
   * Tests different directory contexts to debug file visibility issues
   */
  async testDirectoryContexts() {
    try {
      this.isLoading = true;
      logger.log("[BackupFilesList] Testing directory contexts");

      const debugOutput = await this.platformService.testDirectoryContexts();

      logger.log(
        "[BackupFilesList] Directory context test results:",
        debugOutput,
      );

      // Show the debug output in a notification or alert
      this.$notify(
        {
          group: "alert",
          type: "info",
          title: "Directory Context Test",
          text: "Directory context test completed. Check the console for detailed results.",
        },
        5000,
      );

      // Also log the full output to console for easy access
      logger.log("=== Directory Context Test Results ===");
      logger.log(debugOutput);
      logger.log("=== End Test Results ===");
    } catch (error) {
      logger.error(
        "[BackupFilesList] Failed to test directory contexts:",
        error,
      );
      this.$notify(
        {
          group: "alert",
          type: "danger",
          title: "Context Test Failed",
          text: "Failed to test directory contexts. Check the console for details.",
        },
        5000,
      );
    } finally {
      this.isLoading = false;
    }
  }

  /**
   * Refreshes the file list after a backup is created
   * This method can be called from parent components
   */
  async refreshAfterSave() {
    logger.log("[BackupFilesList] refreshAfterSave called");
    await this.refreshFiles();
  }

  /**
   * Opens a specific file in the device's file viewer
   * @param fileUri - URI of the file to open
   * @param fileName - Name of the file for display
   */
  async openFile(fileUri: string, fileName: string) {
    try {
      const result = await this.platformService.openFile(fileUri, fileName);

      if (result.success) {
        logger.log("[BackupFilesList] File opened successfully:", {
          fileName,
          timestamp: new Date().toISOString(),
        });
      } else {
        throw new Error(result.error || "Failed to open file");
      }
    } catch (error) {
      logger.error("[BackupFilesList] Failed to open file:", error);
      this.$notify(
        {
          group: "alert",
          type: "danger",
          title: "Error Opening File",
          text: `Failed to open ${fileName}. ${error instanceof Error ? error.message : String(error)}`,
        },
        5000,
      );
    }
  }

  /**
   * Opens the backup directory in the device's file explorer
   */
  async openBackupDirectory() {
    try {
      const result = await this.platformService.openBackupDirectory();

      if (result.success) {
        logger.log("[BackupFilesList] Backup directory opened successfully:", {
          timestamp: new Date().toISOString(),
        });
      } else {
        throw new Error(result.error || "Failed to open backup directory");
      }
    } catch (error) {
      logger.error("[BackupFilesList] Failed to open backup directory:", error);
      this.$notify(
        {
          group: "alert",
          type: "danger",
          title: "Error Opening Directory",
          text: `Failed to open backup directory. ${error instanceof Error ? error.message : String(error)}`,
        },
        5000,
      );
    }
  }

  /**
   * Gets the count of files for a specific type
   * Note: The 'All' tab count is sometimes too small. Logging for debugging.
   */
  getFileCountByType(type: "all" | "contacts" | "seed" | "other"): number {
    let count;
    if (type === "all") {
      count = this.backupFiles.length;
      logger.log(
        "[BackupFilesList] getFileCountByType (All):",
        count,
        this.backupFiles,
      );
      return count;
    }
    count = this.backupFiles.filter((file) => file.type === type).length;
    logger.log(`[BackupFilesList] getFileCountByType (${type}):`, count);
    return count;
  }

  /**
   * Gets the appropriate icon for a file type
   * @param type - File type
   * @returns FontAwesome icon name
   */
  getFileIcon(type: "contacts" | "seed" | "other"): string {
    switch (type) {
      case "contacts":
        return "address-book";
      case "seed":
        return "key";
      default:
        return "file-alt";
    }
  }

  /**
   * Gets the appropriate icon color for a file type
   * @param type - File type
   * @returns CSS color class
   */
  getFileIconColor(type: "contacts" | "seed" | "other"): string {
    switch (type) {
      case "contacts":
        return "text-blue-500";
      case "seed":
        return "text-orange-500";
      default:
        return "text-gray-500";
    }
  }

  /**
   * Gets the appropriate badge color for a file type
   * @param type - File type
   * @returns CSS color class
   */
  getTypeBadgeColor(type: "contacts" | "seed" | "other"): string {
    switch (type) {
      case "contacts":
        return "bg-blue-100 text-blue-800";
      case "seed":
        return "bg-orange-100 text-orange-800";
      default:
        return "bg-gray-100 text-gray-800";
    }
  }

  /**
   * Formats file size in human-readable format
   * @param bytes - File size in bytes
   * @returns Formatted file size string
   */
  formatFileSize(bytes: number): string {
    if (bytes === 0) return "0 Bytes";

    const k = 1024;
    const sizes = ["Bytes", "KB", "MB", "GB"];
    const i = Math.floor(Math.log(bytes) / Math.log(k));

    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
  }

  /**
   * Debug method to test file discovery
   * Can be called from browser console for troubleshooting
   */
  public async debugFileDiscovery() {
    try {
      logger.log("[BackupFilesList] Starting debug file discovery...");

      // Test the platform service's test methods
      const platformService = PlatformServiceFactory.getInstance();

      // Test listing all user files
      const allFilesResult = await platformService.testListUserFiles();
      logger.log(
        "[BackupFilesList] All user files test result:",
        allFilesResult,
      );

      // Test listing backup files specifically
      const backupFilesResult = await platformService.testBackupFiles();
      logger.log(
        "[BackupFilesList] Backup files test result:",
        backupFilesResult,
      );

      // Note: testListAllBackupFiles method is not part of the PlatformService interface
      // It exists only in CapacitorPlatformService implementation
      // If needed, this could be added to the interface or called via type assertion

      // Test debug listing all files without filtering (if available)
      if ("debugListAllFiles" in platformService) {
        const debugAllFiles = await (
          platformService as any
        ).debugListAllFiles();
        logger.log("[BackupFilesList] Debug all files (no filtering):", {
          count: debugAllFiles.length,
          files: debugAllFiles.map((f: any) => ({
            name: f.name,
            path: f.path,
            size: f.size,
          })),
        });
      }

      // Test comprehensive step-by-step debug (if available)
      if ("debugFileDiscoveryStepByStep" in platformService) {
        const stepByStepDebug = await (
          platformService as any
        ).debugFileDiscoveryStepByStep();
        logger.log(
          "[BackupFilesList] Step-by-step debug output:",
          stepByStepDebug,
        );
      }

      return {
        allFiles: allFilesResult,
        backupFiles: backupFilesResult,
        currentBackupFiles: this.backupFiles,
        debugAllFiles:
          "debugListAllFiles" in platformService
            ? await (platformService as any).debugListAllFiles()
            : null,
      };
    } catch (error) {
      logger.error("[BackupFilesList] Debug file discovery failed:", error);
      throw error;
    }
  }

  @Watch("platformCapabilities.hasFileSystem", { immediate: true })
  async onFileSystemCapabilityChanged(newVal: boolean) {
    if (newVal) {
      await this.refreshFiles();
    }
  }
}
</script>
