<template>
  <div class="lazy-loading-example">
    <!-- Loading state with Suspense -->
    <Suspense>
      <template #default>
        <!-- Main content with lazy-loaded components -->
        <div class="content">
          <h1>Lazy Loading Example</h1>

          <!-- Lazy-loaded heavy component -->
          <LazyHeavyComponent
            v-if="showHeavyComponent"
            :data="heavyComponentData"
            @data-processed="handleDataProcessed"
          />

          <!-- Conditionally loaded components -->
          <LazyQRScanner v-if="showQRScanner" @qr-detected="handleQRDetected" />

          <LazyThreeJSViewer
            v-if="showThreeJS"
            :model-url="threeJSModelUrl"
            @model-loaded="handleModelLoaded"
          />

          <!-- Route-based lazy loading -->
          <router-view v-slot="{ Component }">
            <component :is="Component" />
          </router-view>
        </div>
      </template>

      <!-- Loading fallback -->
      <template #fallback>
        <div class="loading-fallback">
          <div class="spinner"></div>
          <p>Loading components...</p>
        </div>
      </template>
    </Suspense>

    <!-- Control buttons -->
    <div class="controls">
      <button @click="toggleHeavyComponent">
        {{ showHeavyComponent ? "Hide" : "Show" }} Heavy Component
      </button>
      <button @click="toggleQRScanner">
        {{ showQRScanner ? "Hide" : "Show" }} QR Scanner
      </button>
      <button @click="toggleThreeJS">
        {{ showThreeJS ? "Hide" : "Show" }} 3D Viewer
      </button>
    </div>
  </div>
</template>

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

/**
 * Lazy Loading Example Component
 *
 * Demonstrates various lazy loading patterns with vue-facing-decorator:
 * - defineAsyncComponent for heavy components
 * - Conditional loading based on user interaction
 * - Suspense for loading states
 * - Route-based lazy loading
 *
 * @author Matthew Raymer
 * @version 1.0.0
 */
@Component({
  name: "LazyLoadingExample",
  components: {
    // Lazy-loaded components with loading and error states
    LazyHeavyComponent: defineAsyncComponent({
      loader: () => import("./sub-components/HeavyComponent.vue"),
      loadingComponent: {
        template: '<div class="loading">Loading heavy component...</div>',
      },
      errorComponent: {
        template: '<div class="error">Failed to load heavy component</div>',
      },
      delay: 200, // Show loading component after 200ms
      timeout: 10000, // Timeout after 10 seconds
    }),

    LazyQRScanner: defineAsyncComponent({
      loader: () => import("./sub-components/QRScannerComponent.vue"),
      loadingComponent: {
        template: '<div class="loading">Initializing QR scanner...</div>',
      },
      errorComponent: {
        template: '<div class="error">QR scanner not available</div>',
      },
    }),

    LazyThreeJSViewer: defineAsyncComponent({
      loader: () => import("./sub-components/ThreeJSViewer.vue"),
      loadingComponent: {
        template: '<div class="loading">Loading 3D viewer...</div>',
      },
      errorComponent: {
        template: '<div class="error">3D viewer failed to load</div>',
      },
    }),
  },
})
export default class LazyLoadingExample extends Vue {
  // Component state
  @Prop({ default: false }) readonly initialLoadHeavy!: boolean;

  // Reactive properties
  showHeavyComponent = false;
  showQRScanner = false;
  showThreeJS = false;

  // Component data
  heavyComponentData = {
    items: Array.from({ length: 1000 }, (_, i) => ({
      id: i,
      name: `Item ${i}`,
    })),
    filters: { category: "all", status: "active" },
    sortBy: "name",
  };

  threeJSModelUrl = "/models/lupine_plant/scene.gltf";

  // Computed properties
  get isLoadingAnyComponent(): boolean {
    return this.showHeavyComponent || this.showQRScanner || this.showThreeJS;
  }

  get componentCount(): number {
    let count = 0;
    if (this.showHeavyComponent) count++;
    if (this.showQRScanner) count++;
    if (this.showThreeJS) count++;
    return count;
  }

  // Lifecycle hooks
  mounted(): void {
    console.log("[LazyLoadingExample] Component mounted");

    // Initialize based on props
    if (this.initialLoadHeavy) {
      this.showHeavyComponent = true;
    }

    // Preload critical components
    this.preloadCriticalComponents();
  }

  // Methods
  toggleHeavyComponent(): void {
    this.showHeavyComponent = !this.showHeavyComponent;
    console.log(
      "[LazyLoadingExample] Heavy component toggled:",
      this.showHeavyComponent,
    );
  }

  toggleQRScanner(): void {
    this.showQRScanner = !this.showQRScanner;
    console.log("[LazyLoadingExample] QR scanner toggled:", this.showQRScanner);
  }

  toggleThreeJS(): void {
    this.showThreeJS = !this.showThreeJS;
    console.log(
      "[LazyLoadingExample] ThreeJS viewer toggled:",
      this.showThreeJS,
    );
  }

  handleDataProcessed(data: any): void {
    console.log("[LazyLoadingExample] Data processed:", data);
    // Handle processed data from heavy component
  }

  handleQRDetected(qrData: string): void {
    console.log("[LazyLoadingExample] QR code detected:", qrData);
    // Handle QR code data
  }

  handleModelLoaded(modelInfo: any): void {
    console.log("[LazyLoadingExample] 3D model loaded:", modelInfo);
    // Handle 3D model loaded event
  }

  /**
   * Preload critical components for better UX
   */
  private preloadCriticalComponents(): void {
    // Preload components that are likely to be used
    if (process.env.NODE_ENV === "production") {
      // In production, preload based on user behavior patterns
      this.preloadComponent(
        () => import("./sub-components/HeavyComponent.vue"),
      );
    }
  }

  /**
   * Preload a component without rendering it
   */
  private preloadComponent(componentLoader: () => Promise<any>): void {
    componentLoader().catch((error) => {
      console.warn("[LazyLoadingExample] Preload failed:", error);
    });
  }

  // Watchers
  @Watch("showHeavyComponent")
  onHeavyComponentToggle(newValue: boolean): void {
    if (newValue) {
      // Component is being shown - could trigger analytics
      console.log("[LazyLoadingExample] Heavy component shown");
    }
  }

  @Watch("componentCount")
  onComponentCountChange(newCount: number): void {
    console.log("[LazyLoadingExample] Active component count:", newCount);
  }
}
</script>

<style scoped>
.lazy-loading-example {
  padding: 20px;
  max-width: 1200px;
  margin: 0 auto;
}

.content {
  margin-bottom: 20px;
}

.controls {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 20px;
}

.controls button {
  padding: 10px 20px;
  border: 1px solid #ccc;
  border-radius: 4px;
  background: #f8f9fa;
  cursor: pointer;
  transition: background-color 0.2s;
}

.controls button:hover {
  background: #e9ecef;
}

.loading-fallback {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 40px;
  text-align: center;
}

.spinner {
  width: 40px;
  height: 40px;
  border: 4px solid #f3f3f3;
  border-top: 4px solid #3498db;
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin-bottom: 20px;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

.loading {
  padding: 20px;
  text-align: center;
  color: #666;
}

.error {
  padding: 20px;
  text-align: center;
  color: #dc3545;
  background: #f8d7da;
  border: 1px solid #f5c6cb;
  border-radius: 4px;
}
</style>
