<template>
  <div class="qr-scanner-component">
    <h2>QR Code Scanner</h2>

    <!-- Camera controls -->
    <div class="camera-controls">
      <button :disabled="isScanning || !hasCamera" @click="startScanning">
        {{ isScanning ? "Scanning..." : "Start Scanning" }}
      </button>
      <button :disabled="!isScanning" @click="stopScanning">
        Stop Scanning
      </button>
      <button
        :disabled="!isScanning || cameras.length <= 1"
        @click="switchCamera"
      >
        Switch Camera
      </button>
    </div>

    <!-- Camera status -->
    <div class="camera-status">
      <div v-if="!hasCamera" class="status-error">
        <p>Camera not available</p>
        <p class="status-detail">
          This device doesn't have a camera or camera access is denied.
        </p>
      </div>

      <div v-else-if="!isScanning" class="status-info">
        <p>Camera ready</p>
        <p class="status-detail">
          Click "Start Scanning" to begin QR code detection.
        </p>
      </div>

      <div v-else class="status-scanning">
        <p>Scanning for QR codes...</p>
        <p class="status-detail">Point camera at a QR code to scan.</p>
      </div>
    </div>

    <!-- Camera view -->
    <div v-if="isScanning && hasCamera" class="camera-container">
      <video
        ref="videoElement"
        class="camera-video"
        autoplay
        playsinline
        muted
      ></video>

      <!-- Scanning overlay -->
      <div class="scanning-overlay">
        <div class="scan-frame"></div>
        <div class="scan-line"></div>
      </div>
    </div>

    <!-- Scan results -->
    <div v-if="scanResults.length > 0" class="scan-results">
      <h3>Scan Results ({{ scanResults.length }})</h3>

      <div class="results-list">
        <div
          v-for="(result, index) in scanResults"
          :key="index"
          class="result-item"
        >
          <div class="result-header">
            <span class="result-number">#{{ index + 1 }}</span>
            <span class="result-time">{{ formatTime(result.timestamp) }}</span>
          </div>
          <div class="result-content">
            <div class="qr-data"><strong>Data:</strong> {{ result.data }}</div>
            <div class="qr-format">
              <strong>Format:</strong> {{ result.format }}
            </div>
          </div>
          <div class="result-actions">
            <button class="copy-btn" @click="copyToClipboard(result.data)">
              Copy
            </button>
            <button class="remove-btn" @click="removeResult(index)">
              Remove
            </button>
          </div>
        </div>
      </div>

      <div class="results-actions">
        <button class="clear-btn" @click="clearResults">
          Clear All Results
        </button>
        <button class="export-btn" @click="exportResults">
          Export Results
        </button>
      </div>
    </div>

    <!-- Settings panel -->
    <div class="settings-panel">
      <h3>Scanner Settings</h3>

      <div class="setting-group">
        <label>
          <input v-model="settings.continuousScanning" type="checkbox" />
          Continuous Scanning
        </label>
        <p class="setting-description">
          Automatically scan multiple QR codes without stopping
        </p>
      </div>

      <div class="setting-group">
        <label>
          <input v-model="settings.audioFeedback" type="checkbox" />
          Audio Feedback
        </label>
        <p class="setting-description">Play sound when QR code is detected</p>
      </div>

      <div class="setting-group">
        <label>
          <input v-model="settings.vibrateOnScan" type="checkbox" />
          Vibration Feedback
        </label>
        <p class="setting-description">
          Vibrate device when QR code is detected
        </p>
      </div>

      <div class="setting-group">
        <label>Scan Interval (ms):</label>
        <input
          v-model.number="settings.scanInterval"
          type="number"
          min="100"
          max="5000"
          step="100"
        />
        <p class="setting-description">
          Time between scans (lower = faster, higher = more accurate)
        </p>
      </div>
    </div>
  </div>
</template>

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

interface ScanResult {
  data: string;
  format: string;
  timestamp: Date;
}

interface ScannerSettings {
  continuousScanning: boolean;
  audioFeedback: boolean;
  vibrateOnScan: boolean;
  scanInterval: number;
}

/**
 * QR Scanner Component
 *
 * Demonstrates lazy loading for camera-dependent features.
 * This component would benefit from lazy loading as it requires
 * camera permissions and heavy camera processing libraries.
 *
 * @author Matthew Raymer
 * @version 1.0.0
 */
@Component({
  name: "QRScannerComponent",
})
export default class QRScannerComponent extends Vue {
  // Component state
  isScanning = false;
  hasCamera = false;
  cameras: MediaDeviceInfo[] = [];
  currentCameraIndex = 0;

  // Video element reference
  videoElement: HTMLVideoElement | null = null;

  // Scan results
  scanResults: ScanResult[] = [];

  // Scanner settings
  settings: ScannerSettings = {
    continuousScanning: true,
    audioFeedback: true,
    vibrateOnScan: true,
    scanInterval: 500,
  };

  // Internal state
  private stream: MediaStream | null = null;
  private scanInterval: number | null = null;
  private lastScanTime = 0;

  // Lifecycle hooks
  async mounted(): Promise<void> {
    console.log("[QRScannerComponent] Component mounted");
    await this.initializeCamera();
  }

  beforeUnmount(): void {
    this.stopScanning();
    console.log("[QRScannerComponent] Component unmounting");
  }

  // Methods
  async initializeCamera(): Promise<void> {
    try {
      // Check if camera is available
      const devices = await navigator.mediaDevices.enumerateDevices();
      this.cameras = devices.filter((device) => device.kind === "videoinput");
      this.hasCamera = this.cameras.length > 0;

      if (this.hasCamera) {
        console.log(
          "[QRScannerComponent] Camera available:",
          this.cameras.length,
          "devices",
        );
      } else {
        console.warn("[QRScannerComponent] No camera devices found");
      }
    } catch (error) {
      console.error("[QRScannerComponent] Camera initialization error:", error);
      this.hasCamera = false;
    }
  }

  async startScanning(): Promise<void> {
    if (!this.hasCamera || this.isScanning) return;

    try {
      console.log("[QRScannerComponent] Starting QR scanning...");

      // Get camera stream
      const constraints = {
        video: {
          deviceId: this.cameras[this.currentCameraIndex]?.deviceId,
        },
      };

      this.stream = await navigator.mediaDevices.getUserMedia(constraints);

      // Set up video element
      this.videoElement = this.$refs.videoElement as HTMLVideoElement;
      if (this.videoElement) {
        this.videoElement.srcObject = this.stream;
        await this.videoElement.play();
      }

      this.isScanning = true;

      // Start QR code detection
      this.startQRDetection();

      console.log("[QRScannerComponent] QR scanning started");
    } catch (error) {
      console.error("[QRScannerComponent] Failed to start scanning:", error);
      this.hasCamera = false;
    }
  }

  stopScanning(): void {
    if (!this.isScanning) return;

    console.log("[QRScannerComponent] Stopping QR scanning...");

    // Stop QR detection
    this.stopQRDetection();

    // Stop camera stream
    if (this.stream) {
      this.stream.getTracks().forEach((track) => track.stop());
      this.stream = null;
    }

    // Clear video element
    if (this.videoElement) {
      this.videoElement.srcObject = null;
      this.videoElement = null;
    }

    this.isScanning = false;
    console.log("[QRScannerComponent] QR scanning stopped");
  }

  async switchCamera(): Promise<void> {
    if (this.cameras.length <= 1) return;

    // Stop current scanning
    this.stopScanning();

    // Switch to next camera
    this.currentCameraIndex =
      (this.currentCameraIndex + 1) % this.cameras.length;

    // Restart scanning with new camera
    await this.startScanning();

    console.log(
      "[QRScannerComponent] Switched to camera:",
      this.currentCameraIndex,
    );
  }

  private startQRDetection(): void {
    if (!this.settings.continuousScanning) return;

    this.scanInterval = window.setInterval(() => {
      this.detectQRCode();
    }, this.settings.scanInterval);
  }

  private stopQRDetection(): void {
    if (this.scanInterval) {
      clearInterval(this.scanInterval);
      this.scanInterval = null;
    }
  }

  private async detectQRCode(): Promise<void> {
    if (!this.videoElement || !this.isScanning) return;

    const now = Date.now();
    if (now - this.lastScanTime < this.settings.scanInterval) return;

    try {
      // Simulate QR code detection
      // In a real implementation, you would use a QR code library like jsQR
      const detectedQR = await this.simulateQRDetection();

      if (detectedQR) {
        this.addScanResult(detectedQR);
        this.lastScanTime = now;
      }
    } catch (error) {
      console.error("[QRScannerComponent] QR detection error:", error);
    }
  }

  private async simulateQRDetection(): Promise<ScanResult | null> {
    // Simulate QR code detection with random chance
    if (Math.random() < 0.1) {
      // 10% chance of detection
      const sampleData = [
        "https://example.com/qr1",
        "WIFI:S:MyNetwork;T:WPA;P:password123;;",
        "BEGIN:VCARD\nVERSION:3.0\nFN:John Doe\nTEL:+1234567890\nEND:VCARD",
        "otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example",
      ];

      const formats = ["URL", "WiFi", "vCard", "TOTP"];
      const randomIndex = Math.floor(Math.random() * sampleData.length);

      return {
        data: sampleData[randomIndex],
        format: formats[randomIndex],
        timestamp: new Date(),
      };
    }

    return null;
  }

  private addScanResult(result: ScanResult): void {
    // Check for duplicates
    const isDuplicate = this.scanResults.some(
      (existing) => existing.data === result.data,
    );

    if (!isDuplicate) {
      this.scanResults.unshift(result);

      // Provide feedback
      this.provideFeedback();

      // Emit event
      this.$emit("qr-detected", result.data);

      console.log("[QRScannerComponent] QR code detected:", result.data);
    }
  }

  private provideFeedback(): void {
    // Audio feedback
    if (this.settings.audioFeedback) {
      this.playBeepSound();
    }

    // Vibration feedback
    if (this.settings.vibrateOnScan && "vibrate" in navigator) {
      navigator.vibrate(100);
    }
  }

  private playBeepSound(): void {
    // Create a simple beep sound
    const audioContext = new (window.AudioContext ||
      (window as any).webkitAudioContext)();
    const oscillator = audioContext.createOscillator();
    const gainNode = audioContext.createGain();

    oscillator.connect(gainNode);
    gainNode.connect(audioContext.destination);

    oscillator.frequency.setValueAtTime(800, audioContext.currentTime);
    oscillator.type = "sine";

    gainNode.gain.setValueAtTime(0.1, audioContext.currentTime);
    gainNode.gain.exponentialRampToValueAtTime(
      0.01,
      audioContext.currentTime + 0.1,
    );

    oscillator.start(audioContext.currentTime);
    oscillator.stop(audioContext.currentTime + 0.1);
  }

  copyToClipboard(text: string): void {
    navigator.clipboard
      .writeText(text)
      .then(() => {
        console.log("[QRScannerComponent] Copied to clipboard:", text);
      })
      .catch((error) => {
        console.error("[QRScannerComponent] Failed to copy:", error);
      });
  }

  removeResult(index: number): void {
    this.scanResults.splice(index, 1);
  }

  clearResults(): void {
    this.scanResults = [];
    console.log("[QRScannerComponent] Results cleared");
  }

  exportResults(): void {
    const data = JSON.stringify(this.scanResults, null, 2);
    const blob = new Blob([data], { type: "application/json" });
    const url = URL.createObjectURL(blob);

    const a = document.createElement("a");
    a.href = url;
    a.download = `qr-scan-results-${new Date().toISOString().split("T")[0]}.json`;
    a.click();

    URL.revokeObjectURL(url);
    console.log("[QRScannerComponent] Results exported");
  }

  formatTime(date: Date): string {
    return date.toLocaleTimeString();
  }

  // Event emitters
  @Emit("qr-detected")
  emitQRDetected(data: string): string {
    return data;
  }
}
</script>

<style scoped>
.qr-scanner-component {
  padding: 20px;
  border: 1px solid #ddd;
  border-radius: 8px;
  background: #f9f9f9;
}

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

.camera-controls button {
  padding: 8px 16px;
  border: 1px solid #ccc;
  border-radius: 4px;
  background: #fff;
  cursor: pointer;
  transition: background-color 0.2s;
}

.camera-controls button:hover:not(:disabled) {
  background: #e9ecef;
}

.camera-controls button:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.camera-status {
  margin-bottom: 20px;
  padding: 15px;
  border-radius: 4px;
}

.status-error {
  background: #f8d7da;
  border: 1px solid #f5c6cb;
  color: #721c24;
}

.status-info {
  background: #d1ecf1;
  border: 1px solid #bee5eb;
  color: #0c5460;
}

.status-scanning {
  background: #d4edda;
  border: 1px solid #c3e6cb;
  color: #155724;
}

.status-detail {
  margin-top: 5px;
  font-size: 0.9em;
  opacity: 0.8;
}

.camera-container {
  position: relative;
  width: 100%;
  max-width: 400px;
  height: 300px;
  margin: 20px auto;
  border: 2px solid #ddd;
  border-radius: 8px;
  overflow: hidden;
}

.camera-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.scanning-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.scan-frame {
  width: 200px;
  height: 200px;
  border: 2px solid #00ff00;
  border-radius: 8px;
  position: relative;
}

.scan-line {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  background: #00ff00;
  animation: scan 2s linear infinite;
}

@keyframes scan {
  0% {
    top: 0;
  }
  100% {
    top: 100%;
  }
}

.scan-results {
  margin-top: 20px;
}

.results-list {
  max-height: 300px;
  overflow-y: auto;
  border: 1px solid #ddd;
  border-radius: 4px;
  background: #fff;
  margin-bottom: 15px;
}

.result-item {
  padding: 12px;
  border-bottom: 1px solid #eee;
}

.result-item:last-child {
  border-bottom: none;
}

.result-header {
  display: flex;
  justify-content: space-between;
  margin-bottom: 8px;
}

.result-number {
  font-weight: bold;
  color: #007bff;
}

.result-time {
  font-size: 0.85em;
  color: #666;
}

.result-content {
  margin-bottom: 10px;
}

.qr-data,
.qr-format {
  margin-bottom: 5px;
  word-break: break-all;
}

.result-actions {
  display: flex;
  gap: 8px;
}

.copy-btn,
.remove-btn {
  padding: 4px 8px;
  border: 1px solid #ccc;
  border-radius: 3px;
  background: #fff;
  cursor: pointer;
  font-size: 0.8em;
}

.copy-btn:hover {
  background: #e9ecef;
}

.remove-btn:hover {
  background: #f8d7da;
  color: #721c24;
}

.results-actions {
  display: flex;
  gap: 10px;
}

.clear-btn,
.export-btn {
  padding: 8px 16px;
  border: 1px solid #ccc;
  border-radius: 4px;
  background: #fff;
  cursor: pointer;
}

.clear-btn:hover {
  background: #f8d7da;
  color: #721c24;
}

.export-btn:hover {
  background: #d4edda;
  color: #155724;
}

.settings-panel {
  margin-top: 20px;
  padding: 15px;
  background: #f8f9fa;
  border-radius: 4px;
}

.setting-group {
  margin-bottom: 15px;
}

.setting-group label {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: bold;
  margin-bottom: 5px;
}

.setting-group input[type="number"] {
  width: 100px;
  padding: 4px 8px;
  border: 1px solid #ccc;
  border-radius: 3px;
}

.setting-description {
  font-size: 0.85em;
  color: #666;
  margin-top: 3px;
  margin-left: 24px;
}
</style>
