console.log('[viewport.js] Script loading...');

/**
 * Viewport - Manages a single DICOM viewport with Cornerstone
 *
 * Handles image loading, viewport state (zoom, pan, window/level),
 * and series navigation for a single canvas element.
 */
class Viewport {
  constructor(id, canvasElement, projectId) {
    this.id = id;
    this.element = canvasElement;
    this.projectId = projectId;
    this.enabled = false;

    // Store parent cell reference for overlay updates
    // Defensive check: canvas might not be attached to DOM yet in rare race conditions
    this.parentCell = canvasElement?.parentElement || null;
    if (!this.parentCell) {
      console.warn('[Viewport', this.id, '] Canvas element not yet attached to DOM during construction');
    }

    // Viewport state
    this.viewport = null;
    this.windowWidth = null;
    this.windowCenter = null;
    this.zoom = 1;
    this.pan = { x: 0, y: 0 };
    this.rotation = 0;
    this.inverted = false;

    // Series data
    this.seriesId = null;
    this.seriesDocIds = [];
    this.currentImageIndex = 0;
    this.seriesBaseScale = null;
    this.seriesMetadata = null; // Store folder object with metadata

    // Image cache
    this.currentImage = null;
    this.thumbnails = [];

    // Linked mode
    this.linked = false;

    // Event handlers
    this.onImageLoadCallback = null;
    this.onScrollCallback = null;
  }

  /**
   * Enable Cornerstone on this viewport's canvas
   */
  async enable() {
    if (this.enabled) {
      console.warn('[Viewport', this.id, '] Already enabled');
      return;
    }

    try {
      console.log('[Viewport', this.id, '] Enabling Cornerstone... [VERSION 4]');

      // Get parent container dimensions (the .viewport-cell)
      const container = this.element.parentElement;
      if (!container) {
        throw new Error('Canvas element has no parent container - cannot determine dimensions');
      }
      const displayWidth = container.clientWidth;
      const displayHeight = container.clientHeight;
      console.log('[Viewport', this.id, '] Parent container dimensions:', displayWidth, 'x', displayHeight);

      // CRITICAL: Set canvas dimensions BEFORE enabling Cornerstone
      // Must set both the element attributes AND the style for proper sizing
      this.element.width = displayWidth;
      this.element.height = displayHeight;
      this.element.style.width = displayWidth + 'px';
      this.element.style.height = displayHeight + 'px';

      console.log('[Viewport', this.id, '] Canvas sized to:', this.element.width, 'x', this.element.height);

      // Enable Cornerstone - it will use our pre-sized canvas
      cornerstone.enable(this.element);

      // Force resize after enabling (Cornerstone sometimes resets dimensions)
      cornerstone.resize(this.element, true);

      // CRITICAL FIX: Cornerstone creates a nested canvas inside the parent canvas
      // This is invalid HTML and browsers won't render it properly (0x0 size)
      // Solution: Move the cornerstone canvas to be a SIBLING of the parent canvas
      const cornerstoneCanvas = this.element.querySelector('.cornerstone-canvas');
      if (cornerstoneCanvas) {
        console.log('[Viewport', this.id, '] Found nested cornerstone canvas, moving to sibling position...');

        // Remove from parent canvas and insert as sibling
        const parentCell = this.element.parentElement;
        if (!parentCell) {
          throw new Error('Canvas element lost parent container during Cornerstone initialization');
        }
        cornerstoneCanvas.remove();
        parentCell.insertBefore(cornerstoneCanvas, this.element);

        // Set explicit dimensions
        cornerstoneCanvas.width = displayWidth;
        cornerstoneCanvas.height = displayHeight;
        cornerstoneCanvas.style.width = displayWidth + 'px';
        cornerstoneCanvas.style.height = displayHeight + 'px';

        // Hide the original canvas since Cornerstone renders to its own canvas
        this.element.style.display = 'none';

        console.log('[Viewport', this.id, '] Cornerstone canvas repositioned and sized to:', cornerstoneCanvas.width, 'x', cornerstoneCanvas.height);
      }

      this.enabled = true;

      // Debug: Check what Cornerstone created
      console.log('[Viewport', this.id, '] Canvas after enable:', {
        width: this.element.width,
        height: this.element.height,
        style: this.element.getAttribute('style'),
        className: this.element.className
      });

      console.log('[Viewport', this.id, '] ✓ Enabled');
    } catch (error) {
      console.error('[Viewport', this.id, '] Failed to enable:', error);
      throw error;
    }
  }

  /**
   * Disable Cornerstone and cleanup
   */
  disable() {
    if (!this.enabled) {
      return;
    }

    try {
      console.log('[Viewport', this.id, '] Disabling...');
      cornerstone.disable(this.element);
      this.enabled = false;
      this.clear();
      console.log('[Viewport', this.id, '] ✓ Disabled');
    } catch (error) {
      console.error('[Viewport', this.id, '] Failed to disable:', error);
    }
  }

  /**
   * Load a DICOM series into this viewport
   * @param {string} seriesId - Series/folder ID
   * @param {Array<string>} docIds - Array of document IDs
   * @param {Object} metadata - Folder/series metadata
   */
  async loadSeries(seriesId, docIds, metadata) {
    if (!this.enabled) {
      throw new Error(`Viewport ${this.id} is not enabled`);
    }

    if (!docIds || docIds.length === 0) {
      throw new Error('No document IDs provided');
    }

    console.log('[Viewport', this.id, '] Loading series:', seriesId, '- Images:', docIds.length);

    this.seriesId = seriesId;
    this.seriesDocIds = docIds;
    this.currentImageIndex = 0;
    this.seriesBaseScale = null;
    this.seriesMetadata = metadata || { folderName: seriesId };
    this.thumbnails = [];

    // Load first image
    await this.loadImage(0);

    console.log('[Viewport', this.id, '] ✓ Series loaded');
  }

  /**
   * Load a specific image by index from the current series
   * @param {number} index - Image index
   */
  async loadImage(index) {
    if (!this.enabled) {
      throw new Error(`Viewport ${this.id} is not enabled`);
    }

    if (index < 0 || index >= this.seriesDocIds.length) {
      console.error('[Viewport', this.id, '] Invalid image index:', index);
      return;
    }

    const docId = this.seriesDocIds[index];
    console.log('[Viewport', this.id, '] Loading image', index + 1, '/', this.seriesDocIds.length, '- docId:', docId);

    // Get file metadata from series metadata if available
    let fileMetadata = null;
    if (this.seriesMetadata && this.seriesMetadata.files) {
      fileMetadata = this.seriesMetadata.files.find(f => f.docId === docId);
    }

    // Get file from cache or download
    const response = await chrome.runtime.sendMessage({
      type: 'GET_FILE',
      docId: docId,
      projectId: this.projectId,
      filename: fileMetadata?.filename,
      folderPath: this.seriesMetadata?.folderPath || [],
      mimeType: fileMetadata?.mimeType || 'application/dicom'
    });

    if (!response || !response.file) {
      throw new Error(response?.error || 'Image file not found');
    }

    const dataUrl = response.file.dataUrl;

    // Convert data URL to File object for Cornerstone
    const base64 = dataUrl.split(',')[1];
    const mimeType = dataUrl.split(';')[0].split(':')[1] || 'application/dicom';
    const binaryString = atob(base64);
    const bytes = new Uint8Array(binaryString.length);
    for (let i = 0; i < binaryString.length; i++) {
      bytes[i] = binaryString.charCodeAt(i);
    }
    const blob = new Blob([bytes], { type: mimeType });
    const file = new File([blob], 'dicom.dcm', { type: mimeType });

    // Load image with Cornerstone
    const imageId = cornerstoneWADOImageLoader.wadouri.fileManager.add(file);
    const image = await cornerstone.loadImage(imageId);

    console.log('[Viewport', this.id, '] Loaded DICOM image - size:', image.width, 'x', image.height);

    this.currentImage = image;
    this.currentImageIndex = index;

    // Calculate initial scale if this is first image in series
    if (this.seriesBaseScale === null && this.element) {
      const canvasWidth = this.element.clientWidth;
      const canvasHeight = this.element.clientHeight;

      const scaleX = canvasWidth / image.width;
      const scaleY = canvasHeight / image.height;
      this.seriesBaseScale = Math.min(scaleX, scaleY) * 0.9; // 90% to leave margin
    }

    // Calculate initial window/level if not already set
    // CRITICAL: Must account for DICOM rescale slope/intercept
    let initialWindowWidth, initialWindowCenter;

    if (this.windowWidth && this.windowCenter) {
      // Use stored values from previous images in series
      initialWindowWidth = this.windowWidth;
      initialWindowCenter = this.windowCenter;
    } else {
      // Calculate from image data with rescale transformation
      const slope = image.slope !== undefined ? image.slope : 1;
      const intercept = image.intercept !== undefined ? image.intercept : 0;

      // Transform raw pixel values to actual values
      const actualMin = (image.minPixelValue * slope) + intercept;
      const actualMax = (image.maxPixelValue * slope) + intercept;

      // Use full range of actual values
      initialWindowWidth = actualMax - actualMin;
      initialWindowCenter = (actualMax + actualMin) / 2;

      // Fallback to reasonable defaults if calculation fails
      if (!initialWindowWidth || initialWindowWidth <= 0) {
        initialWindowWidth = 256;
      }
      if (initialWindowCenter === undefined || isNaN(initialWindowCenter)) {
        initialWindowCenter = 128;
      }

      console.log('[Viewport', this.id, '] Calculated window/level:', {
        rawMin: image.minPixelValue,
        rawMax: image.maxPixelValue,
        slope: slope,
        intercept: intercept,
        actualMin: actualMin,
        actualMax: actualMax,
        windowWidth: initialWindowWidth,
        windowCenter: initialWindowCenter
      });
    }

    // Create viewport settings
    const viewport = {
      scale: this.seriesBaseScale || 1,
      translation: { x: this.pan.x, y: this.pan.y },
      voi: {
        windowWidth: initialWindowWidth,
        windowCenter: initialWindowCenter
      },
      invert: this.inverted,
      pixelReplication: false,
      rotation: this.rotation,
      hflip: false,
      vflip: false
    };

    // Debug: Log viewport settings before displaying
    console.log('[Viewport', this.id, '] Viewport settings:', JSON.stringify(viewport, null, 2));
    console.log('[Viewport', this.id, '] Image properties:', {
      width: image.width,
      height: image.height,
      minPixelValue: image.minPixelValue,
      maxPixelValue: image.maxPixelValue,
      slope: image.slope,
      intercept: image.intercept,
      color: image.color
    });

    // Display image
    cornerstone.displayImage(this.element, image, viewport);
    this.viewport = cornerstone.getViewport(this.element);

    // CRITICAL: Force immediate render
    try {
      cornerstone.draw(this.element);
      console.log('[Viewport', this.id, '] Force draw called');
    } catch (drawError) {
      console.error('[Viewport', this.id, '] Force draw failed:', drawError);
    }

    // Store window/level for future images
    if (!this.windowWidth) {
      this.windowWidth = this.viewport.voi.windowWidth;
      this.windowCenter = this.viewport.voi.windowCenter;
    }

    console.log('[Viewport', this.id, '] ✓ Image displayed [BUILD 20260113-001]');
    console.log('[Viewport', this.id, '] Actual viewport after display:', JSON.stringify(this.viewport, null, 2));

    // Debug: Check canvas dimensions
    console.log('[Viewport', this.id, '] Canvas element dimensions:', {
      canvasWidth: this.element.width,
      canvasHeight: this.element.height,
      clientWidth: this.element.clientWidth,
      clientHeight: this.element.clientHeight,
      offsetWidth: this.element.offsetWidth,
      offsetHeight: this.element.offsetHeight
    });

    // Debug: Check parent container dimensions
    const cell = this.element.closest('.viewport-cell');
    if (cell) {
      console.log('[Viewport', this.id, '] Parent cell dimensions:', {
        clientWidth: cell.clientWidth,
        clientHeight: cell.clientHeight,
        offsetWidth: cell.offsetWidth,
        offsetHeight: cell.offsetHeight
      });
    }

    const gridContainer = this.element.closest('.viewport-grid');
    if (gridContainer) {
      console.log('[Viewport', this.id, '] Grid container dimensions:', {
        clientWidth: gridContainer.clientWidth,
        clientHeight: gridContainer.clientHeight,
        offsetWidth: gridContainer.offsetWidth,
        offsetHeight: gridContainer.offsetHeight
      });
    }

    // Notify listeners
    if (this.onImageLoadCallback) {
      this.onImageLoadCallback(this.id, index, this.seriesDocIds.length);
    }

    // Notify scroll listeners (for linked mode)
    if (this.onScrollCallback) {
      this.onScrollCallback(this.id, index);
    }

    // Update overlay
    this.updateOverlay();
  }

  /**
   * Navigate to next image in series
   */
  async nextImage() {
    if (this.seriesDocIds.length === 0) return;
    const nextIndex = (this.currentImageIndex + 1) % this.seriesDocIds.length;
    await this.loadImage(nextIndex);
  }

  /**
   * Navigate to previous image in series
   */
  async previousImage() {
    if (this.seriesDocIds.length === 0) return;
    const prevIndex = (this.currentImageIndex - 1 + this.seriesDocIds.length) % this.seriesDocIds.length;
    await this.loadImage(prevIndex);
  }

  /**
   * Set viewport state (zoom, pan, window/level)
   */
  setViewport(viewportSettings) {
    if (!this.enabled || !this.currentImage) {
      return;
    }

    try {
      cornerstone.setViewport(this.element, viewportSettings);
      this.viewport = cornerstone.getViewport(this.element);

      // Update internal state
      this.zoom = this.viewport.scale;
      this.pan = this.viewport.translation;
      this.windowWidth = this.viewport.voi.windowWidth;
      this.windowCenter = this.viewport.voi.windowCenter;
      this.rotation = this.viewport.rotation;
      this.inverted = this.viewport.invert;
    } catch (error) {
      console.error('[Viewport', this.id, '] Failed to set viewport:', error);
    }
  }

  /**
   * Get current viewport state
   */
  getViewport() {
    if (!this.enabled || !this.currentImage) {
      return null;
    }
    return cornerstone.getViewport(this.element);
  }

  /**
   * Clear viewport (remove series and image)
   */
  clear() {
    console.log('[Viewport', this.id, '] Clearing...');

    this.seriesId = null;
    this.seriesDocIds = [];
    this.currentImageIndex = 0;
    this.seriesBaseScale = null;
    this.seriesMetadata = null;
    this.currentImage = null;
    this.thumbnails = [];

    // Reset viewport state
    this.windowWidth = null;
    this.windowCenter = null;
    this.zoom = 1;
    this.pan = { x: 0, y: 0 };
    this.rotation = 0;
    this.inverted = false;

    // Clear canvas if enabled
    if (this.enabled && this.element) {
      try {
        const canvas = this.element;
        const context = canvas.getContext('2d');
        if (context) {
          context.clearRect(0, 0, canvas.width, canvas.height);
        }
      } catch (error) {
        console.warn('[Viewport', this.id, '] Failed to clear canvas:', error);
      }
    }

    this.updateOverlay();
    console.log('[Viewport', this.id, '] ✓ Cleared');
  }

  /**
   * Update viewport overlay with current info
   */
  updateOverlay() {
    // Refresh parent cell reference in case DOM was reorganized
    if (!this.parentCell && this.element.parentElement) {
      this.parentCell = this.element.parentElement;
    }

    // Use stored parent cell reference (more reliable after canvas reorganization)
    const cell = this.parentCell;
    if (!cell) {
      console.warn('[Viewport', this.id, '] No parent cell found for overlay update');
      return;
    }

    const seriesNameEl = cell.querySelector('.series-name');
    const imageCounterEl = cell.querySelector('.image-counter');
    const emptyStateEl = cell.querySelector('.viewport-empty-state');

    if (this.seriesMetadata && this.seriesDocIds.length > 0) {
      // Show series info
      if (seriesNameEl) {
        seriesNameEl.textContent = this.seriesMetadata.folderName || this.seriesId || 'Series';
      }
      if (imageCounterEl) {
        imageCounterEl.textContent = `${this.currentImageIndex + 1} / ${this.seriesDocIds.length}`;
      }
      if (emptyStateEl) {
        emptyStateEl.classList.add('hidden');
      }
    } else {
      // Show empty state
      if (seriesNameEl) {
        seriesNameEl.textContent = '-';
      }
      if (imageCounterEl) {
        imageCounterEl.textContent = '-';
      }
      if (emptyStateEl) {
        emptyStateEl.classList.remove('hidden');
      }
    }
  }

  /**
   * Zoom in
   */
  zoomIn() {
    if (!this.viewport) return;
    const newScale = this.viewport.scale * 1.2;
    this.setViewport({ ...this.viewport, scale: newScale });
  }

  /**
   * Zoom out
   */
  zoomOut() {
    if (!this.viewport) return;
    const newScale = this.viewport.scale / 1.2;
    this.setViewport({ ...this.viewport, scale: newScale });
  }

  /**
   * Reset viewport to initial state
   */
  reset() {
    if (!this.currentImage) return;

    // Calculate window/level with rescale transformation
    const slope = this.currentImage.slope !== undefined ? this.currentImage.slope : 1;
    const intercept = this.currentImage.intercept !== undefined ? this.currentImage.intercept : 0;
    const actualMin = (this.currentImage.minPixelValue * slope) + intercept;
    const actualMax = (this.currentImage.maxPixelValue * slope) + intercept;

    let windowWidth = actualMax - actualMin;
    let windowCenter = (actualMax + actualMin) / 2;

    // Fallback to reasonable defaults
    if (!windowWidth || windowWidth <= 0) {
      windowWidth = 256;
    }
    if (windowCenter === undefined || isNaN(windowCenter)) {
      windowCenter = 128;
    }

    const viewport = {
      scale: this.seriesBaseScale || 1,
      translation: { x: 0, y: 0 },
      voi: {
        windowWidth: windowWidth,
        windowCenter: windowCenter
      },
      invert: false,
      pixelReplication: false,
      rotation: 0,
      hflip: false,
      vflip: false
    };

    this.setViewport(viewport);
  }

  /**
   * Toggle invert
   */
  toggleInvert() {
    if (!this.viewport) return;
    this.setViewport({ ...this.viewport, invert: !this.viewport.invert });
  }

  /**
   * Rotate clockwise
   */
  rotate() {
    if (!this.viewport) return;
    const newRotation = (this.viewport.rotation + 90) % 360;
    this.setViewport({ ...this.viewport, rotation: newRotation });
  }

  /**
   * Adjust window width
   */
  adjustWindowWidth(delta) {
    if (!this.viewport) return;
    const newWindowWidth = Math.max(1, this.viewport.voi.windowWidth + delta);
    this.setViewport({
      ...this.viewport,
      voi: {
        ...this.viewport.voi,
        windowWidth: newWindowWidth
      }
    });
  }

  /**
   * Adjust window center
   */
  adjustWindowCenter(delta) {
    if (!this.viewport) return;
    const newWindowCenter = this.viewport.voi.windowCenter + delta;
    this.setViewport({
      ...this.viewport,
      voi: {
        ...this.viewport.voi,
        windowCenter: newWindowCenter
      }
    });
  }

  /**
   * Pan viewport
   */
  pan(deltaX, deltaY) {
    if (!this.viewport) return;
    this.setViewport({
      ...this.viewport,
      translation: {
        x: this.viewport.translation.x + deltaX,
        y: this.viewport.translation.y + deltaY
      }
    });
  }

  /**
   * Serialize viewport state for save/restore
   */
  serialize() {
    return {
      id: this.id,
      seriesId: this.seriesId,
      seriesDocIds: this.seriesDocIds,
      currentImageIndex: this.currentImageIndex,
      seriesMetadata: this.seriesMetadata,
      viewport: this.viewport,
      linked: this.linked
    };
  }

  /**
   * Restore viewport from serialized state
   */
  async deserialize(state) {
    if (state.seriesId && state.seriesDocIds && state.seriesDocIds.length > 0) {
      await this.loadSeries(state.seriesId, state.seriesDocIds, state.seriesMetadata);

      if (state.currentImageIndex !== 0) {
        await this.loadImage(state.currentImageIndex);
      }

      if (state.viewport) {
        this.setViewport(state.viewport);
      }

      this.linked = state.linked || false;
    }
  }

  /**
   * Check if viewport has content loaded
   */
  hasContent() {
    return this.seriesDocIds.length > 0;
  }

  /**
   * Get series info
   */
  getSeriesInfo() {
    return {
      seriesId: this.seriesId,
      seriesName: this.seriesMetadata?.folderName || this.seriesId,
      imageCount: this.seriesDocIds.length,
      currentImageIndex: this.currentImageIndex
    };
  }
}

// Export for use in other modules
if (typeof module !== 'undefined' && module.exports) {
  module.exports = Viewport;
}

console.log('[viewport.js] ✓ Viewport class defined and available globally');
