<!-- QRScannerDialog.vue -->
<template>
  <div
    v-if="visible && !isNativePlatform"
    class="dialog-overlay z-[60] fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center"
  >
    <div
      class="dialog relative bg-white rounded-lg shadow-xl max-w-lg w-full mx-4"
    >
      <!-- Header -->
      <div
        class="p-4 border-b border-gray-200 flex justify-between items-center"
      >
        <div>
          <h3 class="text-lg font-medium text-gray-900">Scan QR Code</h3>
          <span class="text-xs text-gray-500">v1.1.0</span>
        </div>
        <button
          class="text-gray-400 hover:text-gray-500"
          aria-label="Close dialog"
          @click="close"
        >
          <svg
            class="h-6 w-6"
            fill="none"
            viewBox="0 0 24 24"
            stroke="currentColor"
          >
            <path
              stroke-linecap="round"
              stroke-linejoin="round"
              stroke-width="2"
              d="M6 18L18 6M6 6l12 12"
            />
          </svg>
        </button>
      </div>

      <!-- Scanner -->
      <div class="p-4">
        <div
          v-if="useQRReader && !isNativePlatform"
          class="relative aspect-square"
        >
          <!-- Status Message -->
          <div
            class="absolute top-0 left-0 right-0 bg-black bg-opacity-50 text-white text-center py-2 z-10"
          >
            <div
              v-if="isInitializing"
              class="flex items-center justify-center space-x-2"
            >
              <svg
                class="animate-spin h-5 w-5 text-white"
                xmlns="http://www.w3.org/2000/svg"
                fill="none"
                viewBox="0 0 24 24"
              >
                <circle
                  class="opacity-25"
                  cx="12"
                  cy="12"
                  r="10"
                  stroke="currentColor"
                  stroke-width="4"
                ></circle>
                <path
                  class="opacity-75"
                  fill="currentColor"
                  d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0
          3.042 1.135 5.824 3 7.938l3-2.647z"
                ></path>
              </svg>
              <span>{{ initializationStatus }}</span>
            </div>
            <p
              v-else-if="isScanning"
              class="flex items-center justify-center space-x-2"
            >
              <span
                class="inline-block w-2 h-2 bg-green-500 rounded-full animate-pulse"
              ></span>
              <span>Position QR code in the frame</span>
            </p>
            <p v-else-if="error" class="text-red-300">
              <span class="font-medium">Error:</span> {{ error }}
            </p>
            <p v-else class="flex items-center justify-center space-x-2">
              <span
                class="inline-block w-2 h-2 bg-blue-500 rounded-full"
              ></span>
              <span>Ready to scan</span>
            </p>
          </div>

          <qrcode-stream
            :camera="preferredCamera"
            @decode="onDecode"
            @init="onInit"
            @detect="onDetect"
            @error="onError"
            @camera-on="onCameraOn"
            @camera-off="onCameraOff"
          />

          <!-- Scanning Frame -->
          <div
            class="absolute inset-0 border-2"
            :class="{
              'border-blue-500': !error && !isScanning,
              'border-green-500 animate-pulse': isScanning,
              'border-red-500': error,
            }"
            style="opacity: 0.5; pointer-events: none"
          ></div>

          <!-- Debug Info -->
          <div
            class="absolute bottom-16 left-0 right-0 bg-black bg-opacity-50 text-white text-xs text-center py-1"
          >
            Camera: {{ preferredCamera === "user" ? "Front" : "Back" }} |
            Status: {{ cameraStatus }}
          </div>

          <!-- Camera Switch Button -->
          <button
            class="absolute bottom-4 right-4 bg-white rounded-full p-2 shadow-lg"
            title="Switch camera"
            @click="toggleCamera"
          >
            <svg
              class="h-6 w-6 text-gray-600"
              fill="none"
              viewBox="0 0 24 24"
              stroke="currentColor"
            >
              <path
                stroke-linecap="round"
                stroke-linejoin="round"
                stroke-width="2"
                d="M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 
        011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z"
              />
              <path
                stroke-linecap="round"
                stroke-linejoin="round"
                stroke-width="2"
                d="M15 13a3 3 0 11-6 0 3 3 0 016 0z"
              />
            </svg>
          </button>
        </div>
        <div v-else class="text-center py-8">
          <p class="text-gray-500">
            {{
              isNativePlatform
                ? "Using native camera scanner..."
                : "QR code scanning is not supported in this browser."
            }}
          </p>
          <p v-if="!isNativePlatform" class="text-sm text-gray-400 mt-2">
            Please ensure you're using a modern browser with camera access.
          </p>
        </div>
      </div>

      <!-- Error Banner -->
      <div
        v-if="error"
        class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4"
        role="alert"
      >
        <strong class="font-bold">Camera Error:</strong>
        <span class="block sm:inline">{{ error }}</span>
        <ul class="mt-2 text-sm text-red-600 list-disc list-inside">
          <li v-if="error.includes('No camera found')">
            Check if your device has a camera and it is enabled.
          </li>
          <li v-if="error.includes('denied')">
            Allow camera access in your browser settings and reload the page.
          </li>
          <li v-if="error.includes('in use')">
            Close other applications that may be using the camera.
          </li>
          <li v-if="error.includes('HTTPS')">
            Ensure you are using a secure (HTTPS) connection.
          </li>
          <li
            v-if="
              !error.includes('No camera found') &&
              !error.includes('denied') &&
              !error.includes('in use') &&
              !error.includes('HTTPS')
            "
          >
            Try refreshing the page or using a different browser/device.
          </li>
        </ul>
      </div>

      <!-- Footer -->
      <div class="p-4 border-t border-gray-200">
        <div class="flex flex-col space-y-4">
          <!-- Instructions -->
          <div class="text-sm text-gray-600">
            <ul class="list-disc list-inside space-y-1">
              <li>Ensure the QR code is well-lit and in focus</li>
              <li>Hold your device steady</li>
              <li>The QR code should fit within the scanning frame</li>
            </ul>
          </div>

          <!-- Error Message -->
          <p v-if="error" class="text-red-500 text-sm">{{ error }}</p>

          <!-- Actions -->
          <div class="flex justify-end space-x-2">
            <button
              v-if="error"
              class="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600"
              @click="retryScanning"
            >
              Retry
            </button>
            <button
              class="px-4 py-2 bg-gray-100 text-gray-700 rounded-md hover:bg-gray-200"
              @click="close"
            >
              Cancel
            </button>
            <button
              class="px-4 py-2 bg-gray-500 text-white rounded-md hover:bg-gray-600"
              @click="copyLogs"
            >
              Copy Debug Logs
            </button>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div v-if="errorMessage" class="error-message">{{ errorMessage }}</div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from "vue-facing-decorator";
import { QrcodeStream } from "vue-qrcode-reader";
import { QRScannerOptions } from "@/services/QRScanner/types";
import { logger } from "@/utils/logger";
import { Capacitor } from "@capacitor/core";
import { logCollector } from "@/utils/LogCollector";

interface ScanProps {
  onScan: (result: string) => void;
  onError?: (error: Error) => void;
  options?: QRScannerOptions;
  onClose?: () => void;
}

interface DetectionResult {
  content?: string;
  location?: {
    topLeft: { x: number; y: number };
    topRight: { x: number; y: number };
    bottomLeft: { x: number; y: number };
    bottomRight: { x: number; y: number };
  };
}

@Component({
  components: {
    QrcodeStream,
  },
})
export default class QRScannerDialog extends Vue {
  @Prop({ type: Function, required: true }) onScan!: ScanProps["onScan"];
  @Prop({ type: Function }) onError?: ScanProps["onError"];
  @Prop({ type: Object }) options?: ScanProps["options"];
  @Prop({ type: Function }) onClose?: ScanProps["onClose"];

  // Version
  readonly version = "1.1.0";

  visible = true;
  error: string | null = null;
  useQRReader = __USE_QR_READER__;
  isNativePlatform =
    Capacitor.isNativePlatform() ||
    __IS_MOBILE__ ||
    Capacitor.getPlatform() === "android" ||
    Capacitor.getPlatform() === "ios";

  isInitializing = true;
  isScanning = false;
  preferredCamera: "user" | "environment" = "environment";
  initializationStatus = "Checking camera access...";
  cameraStatus = "Initializing";
  errorMessage = "";

  created() {
    console.log('[QRScannerDialog] created');
    console.log('[QRScannerDialog] Props received:', {
      onScan: typeof this.onScan,
      onError: typeof this.onError,
      options: this.options,
      onClose: typeof this.onClose,
    });
    console.log('[QRScannerDialog] Initial state:', {
      visible: this.visible,
      error: this.error,
      useQRReader: this.useQRReader,
      isNativePlatform: this.isNativePlatform,
      isInitializing: this.isInitializing,
      isScanning: this.isScanning,
      preferredCamera: this.preferredCamera,
      initializationStatus: this.initializationStatus,
      cameraStatus: this.cameraStatus,
      errorMessage: this.errorMessage,
    });
    logger.log("QRScannerDialog platform detection:", {
      capacitorNative: Capacitor.isNativePlatform(),
      isMobile: __IS_MOBILE__,
      platform: Capacitor.getPlatform(),
      useQRReader: this.useQRReader,
      isNativePlatform: this.isNativePlatform,
      userAgent: navigator.userAgent,
      mediaDevices: !!navigator.mediaDevices,
      getUserMedia: !!(
        navigator.mediaDevices && navigator.mediaDevices.getUserMedia
      ),
    });
    if (this.isNativePlatform) {
      logger.log("Closing QR dialog on native platform");
      this.$nextTick(() => this.close());
    }
  }

  mounted() {
    console.log('[QRScannerDialog] mounted');
    // Timer to warn if no QR code detected after 10 seconds
    this._scanTimeout = setTimeout(() => {
      if (!this.isScanning) {
        console.warn('[QRScannerDialog] No QR code detected after 10 seconds');
      }
    }, 10000);
    // Periodic timer to log waiting status every 5 seconds
    this._waitingInterval = setInterval(() => {
      if (!this.isScanning && this.cameraStatus === 'Active') {
        console.log('[QRScannerDialog] Still waiting for QR code detection...');
      }
    }, 5000);
    console.log('[QRScannerDialog] Waiting interval started');
  }

  beforeUnmount() {
    if (this._scanTimeout) {
      clearTimeout(this._scanTimeout);
      console.log('[QRScannerDialog] Scan timeout cleared');
    }
    if (this._waitingInterval) {
      clearInterval(this._waitingInterval);
      console.log('[QRScannerDialog] Waiting interval cleared');
    }
    console.log('[QRScannerDialog] beforeUnmount');
  }

  async onInit(promise: Promise<void>): Promise<void> {
    console.log('[QRScannerDialog] onInit called');
    if (this.isNativePlatform) {
      logger.log("Closing QR dialog on native platform");
      this.$nextTick(() => this.close());
      return;
    }
    this.isInitializing = true;
    console.log('[QRScannerDialog] isInitializing set to', this.isInitializing);
    this.error = null;
    this.initializationStatus = "Checking camera access...";
    console.log('[QRScannerDialog] initializationStatus set to', this.initializationStatus);
    try {
      if (!navigator.mediaDevices) {
        console.log('[QRScannerDialog] Camera API not available');
        throw new Error(
          "Camera API not available. Please ensure you're using HTTPS.",
        );
      }
      const devices = await navigator.mediaDevices.enumerateDevices();
      const videoDevices = devices.filter((device) => device.kind === "videoinput");
      console.log('[QRScannerDialog] videoDevices found:', videoDevices.length);
      if (videoDevices.length === 0) {
        throw new Error("No camera found on this device");
      }
      this.initializationStatus = "Requesting camera permission...";
      console.log('[QRScannerDialog] initializationStatus set to', this.initializationStatus);
      try {
        const stream = await navigator.mediaDevices.getUserMedia({
          video: {
            facingMode: this.preferredCamera,
            width: { ideal: 1280 },
            height: { ideal: 720 },
          },
        });
        stream.getTracks().forEach((track) => track.stop());
        this.initializationStatus = "Camera permission granted...";
        console.log('[QRScannerDialog] initializationStatus set to', this.initializationStatus);
      } catch (permissionError) {
        const error = permissionError as Error;
        console.log('[QRScannerDialog] Camera permission error:', error.name, error.message);
        if (
          error.name === "NotAllowedError" ||
          error.name === "PermissionDeniedError"
        ) {
          throw new Error(
            "Camera access denied. Please grant camera permission and try again.",
          );
        } else if (
          error.name === "NotFoundError" ||
          error.name === "DevicesNotFoundError"
        ) {
          throw new Error(
            "No camera found. Please ensure your device has a camera.",
          );
        } else if (
          error.name === "NotReadableError" ||
          error.name === "TrackStartError"
        ) {
          throw new Error("Camera is in use by another application.");
        } else {
          throw new Error(`Camera error: ${error.message}`);
        }
      }
      this.initializationStatus = "Starting QR scanner...";
      console.log('[QRScannerDialog] initializationStatus set to', this.initializationStatus);
      await promise;
      this.isInitializing = false;
      this.cameraStatus = "Ready";
      console.log('[QRScannerDialog] QR scanner initialized successfully');
      console.log('[QRScannerDialog] cameraStatus set to', this.cameraStatus);
    } catch (error) {
      const wrappedError = error instanceof Error ? error : new Error(String(error));
      this.error = wrappedError.message;
      this.cameraStatus = "Error";
      console.log('[QRScannerDialog] Error initializing QR scanner:', wrappedError.message);
      console.log('[QRScannerDialog] cameraStatus set to', this.cameraStatus);
      if (this.onError) {
        this.onError(wrappedError);
      }
    } finally {
      this.isInitializing = false;
      console.log('[QRScannerDialog] isInitializing set to', this.isInitializing);
    }
  }

  onCameraOn(): void {
    this.cameraStatus = "Active";
    console.log('[QRScannerDialog] Camera turned on successfully');
    console.log('[QRScannerDialog] cameraStatus set to', this.cameraStatus);
  }

  onCameraOff(): void {
    this.cameraStatus = "Off";
    console.log('[QRScannerDialog] Camera turned off');
    console.log('[QRScannerDialog] cameraStatus set to', this.cameraStatus);
  }

  onDetect(result: DetectionResult | Promise<DetectionResult>): void {
    const ts = new Date().toISOString();
    console.log(`[QRScannerDialog] onDetect called at ${ts} with`, result);
    this.isScanning = true;
    this.cameraStatus = "Detecting";
    console.log('[QRScannerDialog] isScanning set to', this.isScanning);
    console.log('[QRScannerDialog] cameraStatus set to', this.cameraStatus);
    const processResult = (detection: DetectionResult | DetectionResult[]) => {
      try {
        console.log(`[QRScannerDialog] onDetect exit at ${new Date().toISOString()} with detection:`, detection);
        // Fallback: If detection is an array, check the first element
        let rawValue: string | undefined;
        if (Array.isArray(detection) && detection.length > 0 && 'rawValue' in detection[0]) {
          rawValue = detection[0].rawValue;
        } else if (detection && typeof detection === 'object' && 'rawValue' in detection && detection.rawValue) {
          rawValue = (detection as any).rawValue;
        }
        if (rawValue) {
          console.log('[QRScannerDialog] Fallback: Detected rawValue, treating as scan:', rawValue);
          this.isInitializing = false;
          this.initializationStatus = 'QR code captured!';
          this.onScan(rawValue);
          try {
            console.log('[QRScannerDialog] About to call close() after scan');
            this.close();
            console.log('[QRScannerDialog] close() called successfully after scan');
          } catch (err) {
            console.error('[QRScannerDialog] Error calling close():', err);
          }
        }
      } catch (error) {
        this.handleError(error);
      } finally {
        this.isScanning = false;
        this.cameraStatus = "Active";
        console.log('[QRScannerDialog] isScanning set to', this.isScanning);
        console.log('[QRScannerDialog] cameraStatus set to', this.cameraStatus);
      }
    };
    if (result instanceof Promise) {
      result
        .then(processResult)
        .catch((error: Error) => this.handleError(error))
        .finally(() => {
          this.isScanning = false;
          this.cameraStatus = "Active";
          console.log('[QRScannerDialog] isScanning set to', this.isScanning);
          console.log('[QRScannerDialog] cameraStatus set to', this.cameraStatus);
        });
    } else {
      processResult(result);
    }
  }

  private handleError(error: unknown): void {
    const wrappedError = error instanceof Error ? error : new Error(String(error));
    this.error = wrappedError.message;
    this.cameraStatus = "Error";
    console.log('[QRScannerDialog] handleError:', wrappedError.message);
    console.log('[QRScannerDialog] cameraStatus set to', this.cameraStatus);
    if (this.onError) {
      this.onError(wrappedError);
    }
  }

  onDecode(result: string): void {
    const ts = new Date().toISOString();
    console.log(`[QRScannerDialog] onDecode called at ${ts} with result:`, result);
    try {
      this.isInitializing = false;
      this.initializationStatus = 'QR code captured!';
      console.log('[QRScannerDialog] UI state updated after scan: isInitializing set to', this.isInitializing, ', initializationStatus set to', this.initializationStatus);
      this.onScan(result);
      this.close();
      console.log(`[QRScannerDialog] onDecode exit at ${new Date().toISOString()}`);
    } catch (error) {
      this.handleError(error);
    }
  }

  toggleCamera(): void {
    const prevCamera = this.preferredCamera;
    this.preferredCamera = this.preferredCamera === "user" ? "environment" : "user";
    console.log('[QRScannerDialog] toggleCamera from', prevCamera, 'to', this.preferredCamera);
    console.log('[QRScannerDialog] preferredCamera set to', this.preferredCamera);
  }

  retryScanning(): void {
    console.log('[QRScannerDialog] retryScanning called');
    this.error = null;
    this.isInitializing = true;
    console.log('[QRScannerDialog] isInitializing set to', this.isInitializing);
    console.log('[QRScannerDialog] Scanning re-initialized');
  }

  close = async (): Promise<void> => {
    console.log('[QRScannerDialog] close called');
    this.visible = false;
    console.log('[QRScannerDialog] visible set to', this.visible);
    // Notify parent/service
    if (typeof this.onClose === 'function') {
      console.log('[QRScannerDialog] Calling onClose prop');
      this.onClose();
    }
    await this.$nextTick();
    if (this.$el && this.$el.parentNode) {
      this.$el.parentNode.removeChild(this.$el);
      console.log('[QRScannerDialog] Dialog element removed from DOM');
    } else {
      console.log('[QRScannerDialog] Dialog element NOT removed from DOM');
    }
  }

  onScanDetect(promisedResult) {
    const ts = new Date().toISOString();
    console.log(`[QRScannerDialog] onScanDetect called at ${ts} with`, promisedResult);
    promisedResult
      .then((result) => {
        console.log(`[QRScannerDialog] onScanDetect exit at ${new Date().toISOString()} with result:`, result);
        this.onScan(result);
      })
      .catch((error) => {
        console.error(`[QRScannerDialog] onScanDetect error at ${new Date().toISOString()}:`, error);
        this.errorMessage = error.message || 'Scan error';
        if (this.onError) this.onError(error);
      });
  }

  onScanError(error) {
    const ts = new Date().toISOString();
    console.error(`[QRScannerDialog] onScanError called at ${ts}:`, error);
    this.errorMessage = error.message || 'Camera error';
    if (this.onError) this.onError(error);
  }

  async startMobileScan() {
    try {
      console.log('[QRScannerDialog] startMobileScan called');
      const scanner = QRScannerFactory.getInstance();
      await scanner.startScan();
    } catch (error) {
      console.error('[QRScannerDialog] Error starting mobile scan:', error);
      if (this.onError) this.onError(error);
    }
  }

  async copyLogs() {
    console.log('[QRScannerDialog] copyLogs called');
    try {
      await navigator.clipboard.writeText(logCollector.getLogs());
      alert('Logs copied to clipboard!');
    } catch (e) {
      alert('Failed to copy logs: ' + (e instanceof Error ? e.message : e));
    }
  }
}
</script>

<style scoped>
.dialog-overlay {
  backdrop-filter: blur(4px);
}

.qrcode-stream {
  width: 100%;
  height: 100%;
}

@keyframes pulse {
  0% {
    opacity: 0.5;
  }
  50% {
    opacity: 0.75;
  }
  100% {
    opacity: 0.5;
  }
}

.animate-pulse {
  animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
</style>
