<template>
  <div v-if="visible" class="dialog-overlay z-[60]">
    <div class="dialog relative">
      <div class="text-lg text-center font-bold relative">
        <h1 id="ViewHeading" class="text-center font-bold">
          {{ dialogHeading }}
        </h1>
        <div :class="closeButtonClasses" @click="close()">
          <font-awesome icon="xmark" class="w-[1em]"></font-awesome>
        </div>
      </div>

      <!-- FEEDBACK: Show if camera preview is not visible after mounting -->
      <div v-if="shouldShowCameraFeedback" :class="cameraFeedbackClasses">
        <strong>Camera preview not started.</strong>
        <div><b>Status:</b> {{ cameraFeedbackMessage }}</div>
      </div>

      <div class="mt-4">
        <template v-if="isRegistered">
          <div v-if="!blob">
            <div :class="sectionDividerClasses">
              <span :class="sectionDividerSpanClasses">
                Take a photo with your camera
              </span>
            </div>
            <div v-if="shouldShowCameraPreview" :class="cameraPreviewClasses">
              <!-- Diagnostic Panel -->
              <div v-if="showDiagnostics" :class="diagnosticsPanelClasses">
                <div class="grid grid-cols-2 gap-2">
                  <div>
                    <p><strong>Camera State:</strong> {{ cameraState }}</p>
                    <p>
                      <strong>State Message:</strong>
                      {{ cameraStateMessage || "None" }}
                    </p>
                    <p><strong>Error:</strong> {{ error || "None" }}</p>
                    <p>
                      <strong>Preview Active:</strong>
                      {{ showCameraPreview ? "Yes" : "No" }}
                    </p>
                    <p>
                      <strong>Stream Active:</strong>
                      {{ !!cameraStream ? "Yes" : "No" }}
                    </p>
                  </div>
                  <div>
                    <p><strong>Browser:</strong> {{ userAgent }}</p>
                    <p>
                      <strong>HTTPS:</strong>
                      {{ isSecureContext ? "Yes" : "No" }}
                    </p>
                    <p>
                      <strong>MediaDevices:</strong>
                      {{ hasMediaDevices ? "Yes" : "No" }}
                    </p>
                    <p>
                      <strong>GetUserMedia:</strong>
                      {{ hasGetUserMedia ? "Yes" : "No" }}
                    </p>
                    <p>
                      <strong>Platform:</strong>
                      {{ platformCapabilities.isMobile ? "Mobile" : "Desktop" }}
                    </p>
                  </div>
                </div>
              </div>

              <!-- Toggle Diagnostics Button -->
              <button
                :class="diagnosticsToggleClasses"
                @click="toggleDiagnostics"
              >
                {{ diagnosticsToggleText }}
              </button>
              <div class="camera-container w-full h-full relative">
                <video
                  ref="videoElement"
                  class="camera-video w-full h-full object-cover"
                  autoplay
                  playsinline
                  muted
                ></video>
                <div :class="cameraControlsClasses">
                  <button
                    :class="cameraControlButtonClasses"
                    @click="capturePhoto"
                  >
                    <font-awesome icon="camera" class="w-[1em]" />
                  </button>
                  <button
                    v-if="shouldShowCameraRotation"
                    :class="cameraControlButtonClasses"
                    @click="rotateCamera"
                  >
                    <font-awesome icon="rotate" class="w-[1em]" />
                  </button>
                </div>
              </div>
            </div>
            <div :class="sectionDividerClasses">
              <span :class="sectionDividerSpanClasses">
                OR choose a file from your device
              </span>
            </div>
            <div class="mt-4">
              <input
                type="file"
                :class="fileInputClasses"
                @change="uploadImageFile"
              />
            </div>
            <div :class="sectionDividerClasses">
              <span :class="sectionDividerSpanClasses">
                OR paste an image URL
              </span>
            </div>
            <div class="flex items-center gap-2 mt-4">
              <input
                v-model="imageUrl"
                type="text"
                :class="urlInputClasses"
                placeholder="https://example.com/image.jpg"
              />
              <button
                v-if="imageUrl"
                :class="acceptUrlButtonClasses"
                @click="acceptUrl"
              >
                <font-awesome icon="check" class="fa-fw" />
              </button>
            </div>
          </div>

          <div v-else>
            <div v-if="uploading" class="flex justify-center">
              <font-awesome
                icon="spinner"
                class="fa-spin fa-3x text-center block px-12 py-12"
              />
            </div>
            <div v-else>
              <div v-if="crop">
                <VuePictureCropper
                  :box-style="{
                    backgroundColor: '#f8f8f8',
                    margin: 'auto',
                  }"
                  :img="blobUrl"
                  :options="{
                    viewMode: 1,
                    dragMode: 'crop',
                    aspectRatio: 1 / 1,
                  }"
                  :class="cropperClasses"
                />
              </div>
              <div v-else>
                <div class="flex justify-center">
                  <img :src="blobUrl" :class="imageContainerClasses" />
                </div>
              </div>
              <div :class="buttonGridClasses">
                <button :class="primaryButtonClasses" @click="uploadImage">
                  <span>Upload</span>
                </button>
                <button
                  v-if="showRetry"
                  :class="secondaryButtonClasses"
                  @click="retryImage"
                >
                  <span>Retry</span>
                </button>
              </div>
            </div>
          </div>
        </template>
        <template v-else>
          <div
            id="noticeBeforeUpload"
            :class="registrationNoticeClasses"
            role="alert"
            aria-live="polite"
          >
            <p class="mb-2">
              Before you can upload a photo, a friend needs to register you.
            </p>
            <button
              :class="registrationButtonClasses"
              @click="handleQRCodeClick"
            >
              Share Your Info
            </button>
          </div>
        </template>
      </div>
    </div>
  </div>
</template>

<script lang="ts">
import axios from "axios";
import { ref } from "vue";
import { Component, Vue } from "vue-facing-decorator";
import VuePictureCropper, { cropper } from "vue-picture-cropper";
import { Capacitor } from "@capacitor/core";
import { DEFAULT_IMAGE_API_SERVER, NotificationIface } from "../constants/app";
import {
  NOTIFY_IMAGE_DIALOG_SETTINGS_ERROR,
  NOTIFY_IMAGE_DIALOG_RETRIEVAL_ERROR,
  NOTIFY_IMAGE_DIALOG_CAPTURE_ERROR,
  NOTIFY_IMAGE_DIALOG_NO_IMAGE_ERROR,
  createImageDialogCameraErrorMessage,
  createImageDialogUploadErrorMessage,
  IMAGE_DIALOG_TIMEOUT_LONG,
  IMAGE_DIALOG_TIMEOUT_MODAL,
} from "../constants/notifications";
import { accessToken } from "../libs/crypto";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "../services/PlatformServiceFactory";
import { PlatformServiceMixin } from "../utils/PlatformServiceMixin";
import { Prop } from "vue-facing-decorator";
import { Router } from "vue-router";

const inputImageFileNameRef = ref<Blob>();

@Component({
  components: { VuePictureCropper },
  mixins: [PlatformServiceMixin],
})
export default class ImageMethodDialog extends Vue {
  $notify!: (notification: NotificationIface, timeout?: number) => void;
  $router!: Router;

  /** Active DID for user authentication */
  activeDid = "";

  /** Current image blob being processed */
  blob?: Blob;

  /** Type of claim for the image */
  claimType: string = "";

  /** Whether to show cropping interface */
  crop: boolean = false;

  /** Name of the selected file */
  fileName?: string;

  /** Callback function to set image URL after upload */
  imageCallback: (imageUrl: string) => void = () => {};

  /** URL for image input */
  imageUrl?: string;

  /** Whether to show retry button */
  showRetry = true;

  /** Upload progress state */
  uploading = false;

  /** Dialog visibility state */
  visible = false;

  /** Whether to show camera preview */
  showCameraPreview = false;

  /** Camera stream reference */
  private cameraStream: MediaStream | null = null;

  /** Current camera facing mode */
  private currentFacingMode: "environment" | "user" = "environment";

  platformService = PlatformServiceFactory.getInstance();
  URL = window.URL || window.webkitURL;

  private platformCapabilities = this.platformService.getCapabilities();

  // Add diagnostic properties
  showDiagnostics = false;
  userAgent = navigator.userAgent;
  isSecureContext = window.isSecureContext;
  hasMediaDevices = !!navigator.mediaDevices;
  hasGetUserMedia = !!(
    navigator.mediaDevices && navigator.mediaDevices.getUserMedia
  );
  cameraState:
    | "off"
    | "initializing"
    | "ready"
    | "active"
    | "error"
    | "permission_denied"
    | "not_found"
    | "in_use" = "off";
  cameraStateMessage?: string;
  error: string | null = null;

  // Props
  @Prop({ default: true }) isRegistered!: boolean;
  @Prop({
    default: "environment",
    validator: (value: string) => ["environment", "user"].includes(value),
  })
  defaultCameraMode!: string;

  /**
   * Computed property for dialog heading text
   * Determines the appropriate heading based on current state
   */
  get dialogHeading(): string {
    if (this.uploading) return "Uploading Image…";
    if (this.blob) return this.crop ? "Crop Image" : "Preview Image";
    if (this.showCameraPreview) return "Upload Image";
    return "Add Photo";
  }

  /**
   * Computed property for camera preview visibility
   * Determines if camera preview should be shown
   */
  get shouldShowCameraPreview(): boolean {
    return this.showCameraPreview && !this.blob;
  }

  /**
   * Computed property for camera feedback visibility
   * Shows feedback when camera preview is not visible after mounting
   */
  get shouldShowCameraFeedback(): boolean {
    return !this.showCameraPreview && !this.blob && this.isRegistered;
  }

  /**
   * Computed property for camera feedback message
   * Provides appropriate feedback based on camera state
   */
  get cameraFeedbackMessage(): string {
    if (this.cameraState === "off") {
      if (this.platformCapabilities.isMobile) {
        return "This mobile browser may not support direct camera access, or the app is treating it as a native app. Try using a desktop browser, or check if your browser supports camera access for web apps.";
      }
      return "Your browser supports camera APIs, but the preview did not start. Try refreshing the page or checking browser permissions.";
    }
    if (this.cameraState === "error") {
      return this.error || this.cameraStateMessage || "Unknown error occurred.";
    }
    return this.cameraStateMessage || "Unknown reason.";
  }

  /**
   * Computed property for button grid classes
   * Determines grid layout based on retry button visibility
   */
  get buttonGridClasses(): string {
    return `grid gap-2 mt-2 ${this.showRetry ? "grid-cols-2" : "grid-cols-1"}`;
  }

  /**
   * Computed property for blob URL
   * Creates object URL for blob display
   */
  get blobUrl(): string {
    return this.blob ? this.createBlobURL(this.blob) : "";
  }

  /**
   * Computed property for diagnostics toggle button text
   * Determines button text based on diagnostics visibility
   */
  get diagnosticsToggleText(): string {
    return this.showDiagnostics ? "Hide Diagnostics" : "Show Diagnostics";
  }

  /**
   * Computed property for camera rotation button visibility
   * Shows rotation button only on mobile platforms
   */
  get shouldShowCameraRotation(): boolean {
    return this.platformCapabilities.isMobile;
  }

  /**
   * Computed property for close button classes
   * Provides consistent styling for the close button
   */
  get closeButtonClasses(): string {
    return "text-2xl text-center px-1 py-0.5 leading-none absolute -right-1 top-0";
  }

  /**
   * Computed property for camera feedback container classes
   * Provides consistent styling for camera feedback messages
   */
  get cameraFeedbackClasses(): string {
    return "bg-red-100 text-red-700 border border-red-400 rounded px-4 py-3 my-4 text-sm";
  }

  /**
   * Computed property for section divider classes
   * Provides consistent styling for section dividers
   */
  get sectionDividerClasses(): string {
    return "border-b border-dashed border-slate-300 text-orange-400 mb-4 font-bold text-sm";
  }

  /**
   * Computed property for section divider span classes
   * Provides consistent styling for divider labels
   */
  get sectionDividerSpanClasses(): string {
    return "block w-fit mx-auto -mb-2.5 bg-white px-2";
  }

  /**
   * Computed property for camera preview container classes
   * Provides consistent styling for camera preview
   */
  get cameraPreviewClasses(): string {
    return "camera-preview relative flex bg-black overflow-hidden mb-4";
  }

  /**
   * Computed property for diagnostics panel classes
   * Provides consistent styling for diagnostics overlay
   */
  get diagnosticsPanelClasses(): string {
    return "absolute top-0 left-0 right-0 bg-black/80 text-white text-xs p-2 pt-8 z-20 overflow-auto max-h-[50vh]";
  }

  /**
   * Computed property for diagnostics toggle button classes
   * Provides consistent styling for diagnostics toggle
   */
  get diagnosticsToggleClasses(): string {
    return "absolute top-2 right-2 bg-black/50 text-white px-2 py-1 rounded text-xs z-30";
  }

  /**
   * Computed property for camera control button classes
   * Provides consistent styling for camera control buttons
   */
  get cameraControlButtonClasses(): string {
    return "bg-white text-slate-800 p-3 rounded-full text-2xl leading-none";
  }

  /**
   * Computed property for camera controls container classes
   * Provides consistent styling for camera controls
   */
  get cameraControlsClasses(): string {
    return "absolute bottom-4 inset-x-0 flex items-center justify-center gap-4";
  }

  /**
   * Computed property for file input classes
   * Provides consistent styling for file input with custom button
   */
  get fileInputClasses(): string {
    return "w-full file:text-center file:bg-gradient-to-b file:from-slate-400 file:to-slate-700 file:shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] file:text-white file:px-3 file:py-2 file:rounded-md file:border-none file:cursor-pointer file:me-2";
  }

  /**
   * Computed property for URL input classes
   * Provides consistent styling for URL input field
   */
  get urlInputClasses(): string {
    return "block w-full rounded border border-slate-400 px-4 py-2";
  }

  /**
   * Computed property for accept URL button classes
   * Provides consistent styling for accept URL button
   */
  get acceptUrlButtonClasses(): string {
    return "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-3 py-2 rounded-md cursor-pointer";
  }

  /**
   * Computed property for image container classes
   * Provides consistent styling for image display
   */
  get imageContainerClasses(): string {
    return "mt-2 rounded max-h-[50vh] max-w-[90vw] object-contain";
  }

  /**
   * Computed property for cropper container classes
   * Provides consistent styling for image cropper
   */
  get cropperClasses(): string {
    return "max-h-[50vh] max-w-[90vw] object-contain";
  }

  /**
   * Computed property for primary button classes
   * Provides consistent styling for primary action buttons
   */
  get primaryButtonClasses(): string {
    return "bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white py-2 px-3 rounded-md";
  }

  /**
   * Computed property for secondary button classes
   * Provides consistent styling for secondary action buttons
   */
  get secondaryButtonClasses(): string {
    return "bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white py-2 px-3 rounded-md";
  }

  /**
   * Computed property for registration notice classes
   * Provides consistent styling for registration notice
   */
  get registrationNoticeClasses(): string {
    return "bg-amber-200 text-amber-900 border-amber-500 border-dashed border text-center rounded-md overflow-hidden px-4 py-3";
  }

  /**
   * Computed property for registration button classes
   * Provides consistent styling for registration button
   */
  get registrationButtonClasses(): string {
    return "inline-block text-md uppercase 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-4 py-2 rounded-md";
  }

  /**
   * Lifecycle hook: Initializes component and retrieves user settings
   * @throws {Error} When settings retrieval fails
   */
  async mounted() {
    try {
      const settings = await this.$accountSettings();
      this.activeDid = settings.activeDid || "";
    } catch (error: unknown) {
      logger.error("Error retrieving settings from database:", error);
      this.$notify(
        {
          group: "alert",
          type: "danger",
          title: "Error",
          text:
            error instanceof Error
              ? error.message
              : NOTIFY_IMAGE_DIALOG_SETTINGS_ERROR.message,
        },
        IMAGE_DIALOG_TIMEOUT_MODAL,
      );
    }
  }

  /**
   * Lifecycle hook: Cleans up camera stream when component is destroyed
   */
  beforeDestroy() {
    this.stopCameraPreview();
  }

  open(setImageFn: (arg: string) => void, claimType: string, crop?: boolean) {
    logger.debug("ImageMethodDialog.open called");
    this.claimType = claimType;
    this.crop = !!crop;
    this.imageCallback = setImageFn;
    this.visible = true;
    this.currentFacingMode = this.defaultCameraMode as "environment" | "user";

    // Start camera preview immediately
    logger.debug("Starting camera preview from open()");
    this.startCameraPreview();
  }

  async uploadImageFile(event: Event) {
    const target = event.target as HTMLInputElement;
    if (!target.files) return;

    inputImageFileNameRef.value = target.files[0];
    const file = inputImageFileNameRef.value;
    if (file != null) {
      const reader = new FileReader();
      reader.onload = async (e) => {
        const data = e.target?.result as ArrayBuffer;
        if (data) {
          const blob = new Blob([new Uint8Array(data)], {
            type: file.type,
          });
          this.blob = blob;
          this.fileName = (file as File).name;
          this.showRetry = false;
        }
      };
      reader.readAsArrayBuffer(file as Blob);
    }
  }

  async acceptUrl() {
    if (this.crop) {
      try {
        const urlBlobResponse = await axios.get(this.imageUrl as string, {
          responseType: "blob",
        });
        const fullUrl = new URL(this.imageUrl as string);
        const fileName = fullUrl.pathname.split("/").pop() as string;
        this.blob = urlBlobResponse.data as Blob;
        this.fileName = fileName;
        this.showRetry = false;
      } catch (error) {
        this.$notify(
          {
            group: "alert",
            type: "danger",
            title: "Error",
            text: NOTIFY_IMAGE_DIALOG_RETRIEVAL_ERROR.message,
          },
          IMAGE_DIALOG_TIMEOUT_LONG,
        );
      }
    } else {
      this.imageCallback(this.imageUrl as string);
      this.close();
    }
  }

  close() {
    this.visible = false;
    this.stopCameraPreview();
    const bottomNav = document.querySelector("#QuickNav") as HTMLElement;
    if (bottomNav) {
      bottomNav.style.display = "";
    }
    this.blob = undefined;
    this.showCameraPreview = false;
  }

  async startCameraPreview() {
    logger.debug("startCameraPreview called");
    logger.debug("Current showCameraPreview state:", this.showCameraPreview);
    logger.debug("Platform capabilities:", this.platformCapabilities);
    logger.debug("MediaDevices available:", !!navigator.mediaDevices);
    logger.debug(
      "getUserMedia available:",
      !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia),
    );

    try {
      this.cameraState = "initializing";
      this.cameraStateMessage = "Requesting camera access...";
      this.showCameraPreview = true;
      await this.$nextTick();

      if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
        throw new Error("Camera API not available in this browser");
      }

      const stream = await navigator.mediaDevices.getUserMedia({
        video: { facingMode: this.currentFacingMode },
      });
      logger.debug("Camera access granted");
      this.cameraStream = stream;
      this.cameraState = "active";
      this.cameraStateMessage = "Camera is active";

      await this.$nextTick();

      const videoElement = this.$refs.videoElement as HTMLVideoElement;
      if (videoElement) {
        videoElement.srcObject = stream;
        await new Promise((resolve) => {
          videoElement.onloadedmetadata = () => {
            videoElement
              .play()
              .then(() => {
                logger.debug("Video element started playing");
                resolve(true);
              })
              .catch((error) => {
                logger.error("Error playing video:", error);
                throw error;
              });
          };
        });
      } else {
        logger.error("Video element not found");
        throw new Error("Video element not found");
      }
    } catch (error) {
      logger.error("Error starting camera preview:", error);
      const errorMessage = createImageDialogCameraErrorMessage(
        error instanceof Error ? error : new Error("Unknown camera error"),
      );
      this.cameraState = "error";
      this.cameraStateMessage = errorMessage;
      this.error = errorMessage;
      this.showCameraPreview = false;
      this.$notify(
        {
          group: "alert",
          type: "danger",
          title: "Error",
          text: errorMessage,
        },
        IMAGE_DIALOG_TIMEOUT_LONG,
      );
    }
  }

  stopCameraPreview() {
    if (this.cameraStream) {
      this.cameraStream.getTracks().forEach((track) => track.stop());
      this.cameraStream = null;
    }
    this.showCameraPreview = false;
    this.cameraState = "off";
    this.cameraStateMessage = "Camera stopped";
    this.error = null;
  }

  async capturePhoto() {
    if (!this.cameraStream) return;

    try {
      const videoElement = this.$refs.videoElement as HTMLVideoElement;
      const canvas = document.createElement("canvas");
      canvas.width = videoElement.videoWidth;
      canvas.height = videoElement.videoHeight;
      const ctx = canvas.getContext("2d");
      ctx?.drawImage(videoElement, 0, 0, canvas.width, canvas.height);

      canvas.toBlob(
        (blob) => {
          if (blob) {
            this.blob = blob;
            this.fileName = `photo_${Date.now()}.jpg`;
            this.showRetry = true;
            this.stopCameraPreview();
          }
        },
        "image/jpeg",
        0.95,
      );
    } catch (error) {
      logger.error("Error capturing photo:", error);
      this.$notify(
        {
          group: "alert",
          type: "danger",
          title: "Error",
          text: NOTIFY_IMAGE_DIALOG_CAPTURE_ERROR.message,
        },
        IMAGE_DIALOG_TIMEOUT_LONG,
      );
    }
  }

  async rotateCamera() {
    // Toggle between front and back cameras
    this.currentFacingMode =
      this.currentFacingMode === "environment" ? "user" : "environment";

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

    // Start new stream with updated facing mode
    await this.startCameraPreview();
  }

  private createBlobURL(blob: Blob): string {
    return URL.createObjectURL(blob);
  }

  async retryImage() {
    this.blob = undefined;
    if (!this.platformCapabilities.isNativeApp) {
      await this.startCameraPreview();
    }
  }

  async uploadImage() {
    this.uploading = true;

    if (this.crop) {
      this.blob = (await cropper?.getBlob()) || undefined;
    }

    const token = await accessToken(this.activeDid);
    const headers = {
      Authorization: "Bearer " + token,
    };
    const formData = new FormData();
    if (!this.blob) {
      this.$notify(
        {
          group: "alert",
          type: "danger",
          title: "Error",
          text: NOTIFY_IMAGE_DIALOG_NO_IMAGE_ERROR.message,
        },
        IMAGE_DIALOG_TIMEOUT_LONG,
      );
      this.uploading = false;
      this.close();
      return;
    }
    formData.append("image", this.blob, this.fileName || "photo.jpg");
    formData.append("claimType", this.claimType);
    try {
      if (
        window.location.hostname === "localhost" &&
        !DEFAULT_IMAGE_API_SERVER.includes("localhost")
      ) {
        logger.log(
          "Using shared image API server, so only users on that server can play with images.",
        );
      }
      const response = await axios.post(
        DEFAULT_IMAGE_API_SERVER + "/image",
        formData,
        { headers },
      );
      this.uploading = false;

      this.close();
      this.imageCallback(response.data.url as string);
    } catch (error: unknown) {
      const errorMessage = createImageDialogUploadErrorMessage(error);

      this.$notify(
        {
          group: "alert",
          type: "danger",
          title: "Error",
          text: errorMessage,
        },
        IMAGE_DIALOG_TIMEOUT_LONG,
      );
      this.uploading = false;
      this.blob = undefined;
      this.close();
    }
  }

  // Add toggle method
  toggleDiagnostics() {
    this.showDiagnostics = !this.showDiagnostics;
  }

  private handleQRCodeClick() {
    if (Capacitor.isNativePlatform()) {
      this.$router.push({ name: "contact-qr-scan-full" });
    } else {
      this.$router.push({ name: "contact-qr" });
    }
  }
}
</script>

<style>
.dialog-overlay {
  z-index: 50;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 1.5rem;
}

.dialog {
  background-color: white;
  padding: 1rem;
  border-radius: 0.5rem;
  width: 100%;
  max-width: 700px;
  max-height: 90vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* Add styles for diagnostic panel */
.diagnostic-panel {
  font-family: monospace;
  white-space: pre-wrap;
  word-break: break-all;
}
</style>
