/** Shopify CDN: Minification failed

Line 17:2 Unexpected "constructor("
Line 18:8 Expected ":"
Line 19:8 Expected ":"
Line 20:8 Expected ":"
Line 21:8 Expected ":"
Line 24:8 Unexpected "initializeWhenReady("
Line 25:7 Unexpected "("
Line 26:14 Expected ":"
Line 28:10 Expected ":"
Line 32:8 Unexpected "initialize("
... and 111 more hidden warnings

**/
class ImageSearch {
  constructor() {
    this.model = null;
    this.isInitialized = false;
    this.productFeatures = new Map();
    this.initializeWhenReady();
  }

  async initializeWhenReady() {
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', () => this.initialize());
    } else {
      this.initialize();
    }
  }

  async initialize() {
    try {
      console.log('Initializing image search...');
      await this.loadModel();
      await this.precomputeProductFeatures();
      this.setupUI();
      this.isInitialized = true;
      console.log('Image search initialized successfully');
    } catch (error) {
      console.error('Initialization error:', error);
    }
  }

  async loadModel() {
    try {
      console.log('Loading MobileNet model...');
      await new Promise((resolve) => {
        const checkDependencies = () => {
          if (window.tf && window.mobilenet) {
            resolve();
          } else {
            setTimeout(checkDependencies, 100);
          }
        };
        checkDependencies();
      });

      this.model = await window.mobilenet.load();
      console.log('MobileNet model loaded successfully');
    } catch (error) {
      console.error('Error loading model:', error);
      throw error;
    }
  }

  async precomputeProductFeatures() {
    try {
      console.log('Precomputing product features...');
      const response = await fetch('/products.json');
      const data = await response.json();
      const products = data.products;

      for (const product of products) {
        if (product.images && product.images.length > 0) {
          try {
            const img = await this.loadImage(product.images[0].src);
            const tensor = tf.browser.fromPixels(img);
            const features = await this.model.infer(tensor, true);
            this.productFeatures.set(product.id, {
              features: features,
              product: product
            });
            tensor.dispose();
          } catch (error) {
            console.error(`Error processing product ${product.id}:`, error);
          }
        }
      }
      console.log(`Precomputed features for ${this.productFeatures.size} products`);
    } catch (error) {
      console.error('Error precomputing features:', error);
    }
  }

  loadImage(url) {
    return new Promise((resolve, reject) => {
      const img = new Image();
      img.crossOrigin = 'anonymous';
      img.onload = () => resolve(img);
      img.onerror = reject;
      img.src = url;
    });
  }

  setupUI() {
    const searchInputWrapper = document.querySelector('.input-group__field--connected');
    if (!searchInputWrapper) {
      console.error('Search input wrapper not found');
      return;
    }

    const container = document.createElement('div');
    container.className = 'image-search-container';

    const fileInput = document.createElement('input');
    fileInput.type = 'file';
    fileInput.accept = 'image/*';
    fileInput.className = 'image-search-input';
    fileInput.style.display = 'none';

    const button = document.createElement('button');
    button.type = 'button';
    button.className = 'search-button__image';
    button.innerHTML = `
      <svg aria-hidden="true" focusable="false" class="icon icon-camera" viewBox="0 0 24 24">
        <path d="M12 15.2a3.2 3.2 0 100-6.4 3.2 3.2 0 000 6.4z"/>
        <path d="M20 4h-3.17l-1.24-1.35A1.99 1.99 0 0014.12 2H9.88c-.56 0-1.1.24-1.47.65L7.17 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-8 13c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5z"/>
      </svg>
    `;

    const resultsContainer = document.createElement('div');
    resultsContainer.className = 'image-search-results';
    resultsContainer.style.display = 'none';

    fileInput.addEventListener('change', (e) => this.handleImageUpload(e));
    button.addEventListener('click', () => fileInput.click());

    container.appendChild(fileInput);
    container.appendChild(button);
    searchInputWrapper.appendChild(container);
    searchInputWrapper.parentElement.appendChild(resultsContainer);
  }

  async handleImageUpload(event) {
    const file = event.target.files[0];
    if (!file) return;

    try {
      this.showLoadingState();
      
      if (!this.model) {
        throw new Error('Model not loaded');
      }

      const img = await this.createImageFromFile(file);
      const tensor = tf.browser.fromPixels(img);
      const features = await this.model.infer(tensor, true);
      tensor.dispose();

      const similarProducts = await this.findSimilarProducts(features);
      this.displayResults(similarProducts);
    } catch (error) {
      console.error('Error processing image:', error);
      this.showError('Error processing image. Please try again.');
    }
  }

  createImageFromFile(file) {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = (e) => {
        const img = new Image();
        img.crossOrigin = 'anonymous';
        img.onload = () => resolve(img);
        img.onerror = reject;
        img.src = e.target.result;
      };
      reader.onerror = reject;
      reader.readAsDataURL(file);
    });
  }

  async findSimilarProducts(uploadedFeatures) {
    const similarities = [];
    
    for (const [productId, data] of this.productFeatures) {
      const similarity = this.computeCosineSimilarity(
        uploadedFeatures.arraySync()[0],
        data.features.arraySync()[0]
      );
      
      similarities.push({
        product: data.product,
        similarity: similarity
      });
    }

    // Sort by similarity score (highest first)
    return similarities
      .sort((a, b) => b.similarity - a.similarity)
      .slice(0, 5); // Return top 5 most similar products
  }

  computeCosineSimilarity(a, b) {
    const dotProduct = a.reduce((sum, val, i) => sum + val * b[i], 0);
    const magnitudeA = Math.sqrt(a.reduce((sum, val) => sum + val * val, 0));
    const magnitudeB = Math.sqrt(b.reduce((sum, val) => sum + val * val, 0));
    return dotProduct / (magnitudeA * magnitudeB);
  }

  displayResults(similarProducts) {
    const resultsContainer = document.querySelector('.image-search-results');
    if (!resultsContainer) return;

    resultsContainer.innerHTML = '';
    resultsContainer.style.display = 'block';

    if (similarProducts.length === 0) {
      resultsContainer.innerHTML = '<div class="no-results">No similar products found</div>';
      return;
    }

    similarProducts.forEach(({ product, similarity }) => {
      const productEl = document.createElement('div');
      productEl.className = 'image-search-result';
      productEl.innerHTML = `
        <img src="${product.images[0]?.src || ''}" alt="${product.title}">
        <div class="image-search-result__info">
          <h3>${product.title}</h3>
          <p>${(product.variants[0]?.price || 0)} ${window.Shopify?.currency?.active || ''}</p>
          <p class="similarity">Similarity: ${Math.round(similarity * 100)}%</p>
          <a href="/products/${product.handle}" class="btn">View Product</a>
        </div>
      `;
      resultsContainer.appendChild(productEl);
    });
  }

  showLoadingState() {
    const resultsContainer = document.querySelector('.image-search-results');
    if (resultsContainer) {
      resultsContainer.innerHTML = '<div class="loading">Processing image...</div>';
      resultsContainer.style.display = 'block';
    }
  }

  showError(message) {
    const resultsContainer = document.querySelector('.image-search-results');
    if (resultsContainer) {
      resultsContainer.innerHTML = `<div class="error">${message}</div>`;
      resultsContainer.style.display = 'block';
    }
  }
}

// Create a single instance when the script loads
const imageSearch = new ImageSearch();