var store = new Store({
  threshold: 0.25,
  maxCount: 5,
  maxThreshold: 15
});

var TINY_FACE_DETECTOR = 1;var SSD_MOBILENETV1 = 2
function getCurrentFaceDetectionNet() {

  selectedFaceDetector = TINY_FACE_DETECTOR
  if (selectedFaceDetector === SSD_MOBILENETV1) {
    return faceapi.nets.ssdMobilenetv1
  }
  if (selectedFaceDetector === TINY_FACE_DETECTOR) {
    return faceapi.nets.tinyFaceDetector
  }
}
function isFaceDetectionModelLoaded() {
  return !!getCurrentFaceDetectionNet().params
}
window.s0 = 224;

var canvas = document.getElementById("chosen_img");
var cc = canvas.getContext("2d");

var detection = document.getElementById("detection");
var detectionCtx = detection.getContext("2d");

var overlay = document.getElementById("overlay");
var overlayCC = overlay.getContext("2d");
var canvas_container = document.getElementById("canvas_container");

var img = new Image();
img.onload = function() {
  console.log(this, 'ghm');
  // check if the picture is taken landscope.
  if (img.width > img.height) {
    // Change max width and max height depends on screen width.
    if (screen < 414) {
      // for Mobile
      imgSizeFit(img, 256, 300);
    } else {
      imgSizeFit(img, 640, 480);
    }
  } else {
    // Change max width and max height depends on screen width.
    if (screen < 414) {
      // for Mobile
      imgSizeFit(img, 256, 450);
    } else {
      imgSizeFit(img, 480, 640);
    }
  }
  //imgSizeFit(img, )

  cc.drawImage(img, 0, 0, canvas.width, canvas.height);
  doMatching(canvas, cc);
};
// set Image src that user chose.

var src = localStorage.getItem("image_data")
if(src){
  img.src = src;
}


var dims = {width:640, height: 480};
var seq = [];
canvas.addEventListener('click', function(e) {
  seq.push([e.layerX/canvas.width*4|0, e.layerY/canvas.height*4|0]);
  if(seq.length>5){
    seq = seq.slice( seq.length - 5 );
  }
  if(seq.map(function(s) {
    return s.join(',')
  }).join('|') === '3,3|3,0|3,3|0,0|0,3'){
    document.body.classList.add( 'DEBUG_MODE' );
    console.log('enter debug mode');
  }
});
function imgSizeFit(img, maxWidth, maxHeight) {
  var ratio = Math.min(
    1,
    maxWidth / img.naturalWidth,
    maxHeight / img.naturalHeight
  );
  var neww = img.naturalWidth * ratio;
  var newh = img.naturalHeight * ratio;
  //canvas_container.style.width = `${neww}px`;
  canvas.setAttribute("width", neww);
  canvas.setAttribute("height", newh);
  /*overlay.setAttribute("width", dims.width);
  overlay.setAttribute("height", dims.height);
  detection.setAttribute("width", dims.width);
  detection.setAttribute("height", dims.height);*/
}
async function doMatching(el, ctx) {
  var inputSize = s0;
  var scoreThreshold = 0.4;

  if (!isFaceDetectionModelLoaded()){
    await getCurrentFaceDetectionNet().load( assetDir );
    await faceapi.loadFaceLandmarkModel(assetDir );
  }
  var options = new faceapi.TinyFaceDetectorOptions( { inputSize, scoreThreshold } );
  detection.setAttribute("width", dims.width);
  detection.setAttribute("height", dims.height);
  overlay.setAttribute("width", dims.width);
  overlay.setAttribute("height", dims.height);
  detectionCtx.clearRect(0,0,dims.width, dims.height);
  if(img.width/dims.width*dims.height>img.height){
    var h = img.height/(img.width/dims.width);
    detectionCtx.drawImage(img, 0, (dims.height-h)/2, dims.width, h);
  }else{
    var w = img.width/(img.height/dims.height);
    detectionCtx.drawImage(img,  (dims.width-w)/2, 0, w, dims.height);
  }


  let result = await faceapi.detectSingleFace( detection, options ).withFaceLandmarks();//.withFaceDescriptor();
  if(result){
    var toPoint = function(p) {
      return new Point(p.x, p.y)
    };

    var jaw = result.landmarks.getJawOutline(),
      nose = result.landmarks.getNose(),
      mouth = result.landmarks.getMouth(),
      leftBrow = result.landmarks.getLeftEyeBrow(),
      rightBrow = result.landmarks.getRightEyeBrow(),

      leftEye = result.landmarks.getLeftEye(),
      rightEye = result.landmarks.getRightEye();

    var top = toPoint(nose[6]).lerp(nose[0], 2).y;
    if(top<0){
      var dtop = -top/dims.height;

      detectionCtx.drawImage(img, dtop*dims.width/2, -top, dims.width-dtop*dims.width, dims.height+top);
      detectionCtx.fillStyle = GetPixel(detectionCtx,4,4);
      detectionCtx.fillRect(0,0,dims.width, -top);
      result = await faceapi.detectSingleFace( detection, options ).withFaceLandmarks();//.withFaceDescriptor();
      if(!result){
        return setTimeout( f, 300 );
      }
      jaw = result.landmarks.getJawOutline(),
        nose = result.landmarks.getNose(),
        mouth = result.landmarks.getMouth(),
        leftBrow = result.landmarks.getLeftEyeBrow(),
        rightBrow = result.landmarks.getRightEyeBrow(),

        leftEye = result.landmarks.getLeftEye(),
        rightEye = result.landmarks.getRightEye();
    }

    overlayCC.clearRect(0,0,dims.width, dims.height);
    faceapi.draw.drawFaceLandmarks( overlayCC, faceapi.resizeResults( result, dims ) );

    overlayCC.fillStyle='blue'; mouth.forEach(function(p, i) { overlayCC.fillText(i+'', p.x, p.y) });
    overlayCC.fillStyle='red'; jaw.forEach(function(p, i) { overlayCC.fillText(i+'', p.x, p.y) });

    overlayCC.fillStyle='yellow'; leftEye.forEach(function(p, i) { overlayCC.fillText(i+'', p.x, p.y) });
    overlayCC.fillStyle='yellow'; rightEye.forEach(function(p, i) { overlayCC.fillText(i+'', p.x, p.y) });

    overlayCC.fillStyle='red'; leftBrow.forEach(function(p, i) { overlayCC.fillText(i+'', p.x, p.y) });
    overlayCC.fillStyle='red'; rightBrow.forEach(function(p, i) { overlayCC.fillText(i+'', p.x, p.y) });

    overlayCC.fillStyle='blue'; nose.forEach(function(p, i) { overlayCC.fillText(i+'', p.x, p.y) });


    var faceMarks = new FaceMarks(result.landmarks);

    var cheek = faceMarks.marks.cheek;

    var ratio = (cheek.left.base[0].distance(cheek.left.base[1])/cheek.right.base[0].distance(cheek.right.base[1]));
    var bad = 2;



    var lips = [];


    lips = lips.concat(faceMarks.marks.lips.top);
    lips = lips.concat(faceMarks.marks.lips.bottom);

    var browsSearchArea = [];

    browsSearchArea.push([
      toPoint(leftBrow[4]),
      toPoint(leftEye[2]).middle(toPoint(leftBrow[4])),
      toPoint(leftBrow[1])
    ]);

    browsSearchArea.push([
      toPoint(rightBrow[0]),
      toPoint(rightEye[1]).middle(toPoint(rightBrow[0])),
      toPoint(rightBrow[3])
    ]);


    var eyes = [], skin;

    if(ratio > bad){
      cheek = [cheek.left.base, cheek.left.bonus1, cheek.left.bonus2];
      browsSearchArea.pop();
      eyes = [
        faceMarks.marks.eyes.left.t1,
        faceMarks.marks.eyes.left.t2,
        faceMarks.marks.eyes.left.t3,
        faceMarks.marks.eyes.left.t4,
        faceMarks.marks.eyes.left.t5,
        faceMarks.marks.eyes.left.t6,
        faceMarks.marks.eyes.left.t7
      ];

      skin = [
        faceMarks.marks.skin.top.left,
        faceMarks.marks.skin.underEye.left,
        faceMarks.marks.skin.underNose.left,
        faceMarks.marks.skin.chin
      ];
    }else if(ratio < 1/bad){
      cheek = [cheek.right.base, cheek.right.bonus1, cheek.right.bonus2];
      browsSearchArea.shift();

      eyes = [
        faceMarks.marks.eyes.right.t1,
        faceMarks.marks.eyes.right.t2,
        faceMarks.marks.eyes.right.t3,
        faceMarks.marks.eyes.right.t4,
        faceMarks.marks.eyes.right.t5,
        faceMarks.marks.eyes.right.t6,
        faceMarks.marks.eyes.right.t7
      ];

      skin = [
        faceMarks.marks.skin.top.right,
        faceMarks.marks.skin.underEye.right,
        faceMarks.marks.skin.underNose.right,
        faceMarks.marks.skin.chin
      ];

    }else{
      cheek = [
        cheek.left.base,
        cheek.left.bonus1,
        cheek.left.bonus2,

        cheek.right.base,
        cheek.right.bonus1,
        cheek.right.bonus2
      ];

      eyes = [
        faceMarks.marks.eyes.left.t1,
        faceMarks.marks.eyes.left.t2,
        faceMarks.marks.eyes.left.t3,
        faceMarks.marks.eyes.left.t4,
        faceMarks.marks.eyes.left.t5,
        faceMarks.marks.eyes.left.t6,
       // faceMarks.marks.eyes.left.t7,

        faceMarks.marks.eyes.right.t1,
        faceMarks.marks.eyes.right.t2,
        faceMarks.marks.eyes.right.t3,
        faceMarks.marks.eyes.right.t4,
        faceMarks.marks.eyes.right.t5,
        faceMarks.marks.eyes.right.t6//,
        //faceMarks.marks.eyes.right.t7
      ];

      skin = [
        faceMarks.marks.skin.top.left,
        faceMarks.marks.skin.top.right,
        faceMarks.marks.skin.underEye.left,
        faceMarks.marks.skin.underEye.right,
        faceMarks.marks.skin.underNose.left,
        faceMarks.marks.skin.underNose.right,
        faceMarks.marks.skin.chin
      ];
    }


    var drawPoly = function(poly, p) {
      var ctx = overlayCC;
      ctx.fillStyle = 'rgba(200,0,100,1)';

      for(var i = 0,_i = poly.length; i < _i; i++ ){
        var point = poly[i];
        ctx.fillText( i + '', point.x, point.y );
      }

      ctx.strokeStyle = 'rgba(200,0,100,0.6)';
      ctx.beginPath();
      for(var i = 0,_i = poly.length; i <= _i; i++ ){
        if(i === 0){
          ctx.moveTo( poly[ i ].x, poly[ i ].y );
        }else{
          ctx.lineTo( poly[ i % _i ].x, poly[ i % _i ].y );
        }
      }
      ctx.stroke();

      var point = poly[0].addClone(poly[1]).add(poly[2]).div(3);

      ctx.fillStyle = '#3ce6f5';
      ctx.fillText( p, point.x-2, point.y+4 );

    };

    cheek.forEach(drawPoly);
    lips.forEach(drawPoly);
    browsSearchArea.forEach(drawPoly);
    eyes.forEach(drawPoly);
    skin.forEach(drawPoly);




    //document.getElementById('ccolors').getContext('2d').clearRect(0,0,120,480);


    extracting = -1;

    var notThis = extractor('skin', detectionCtx, skin, 6, 2);

    extractor('lips', detectionCtx, lips, 5,1, notThis);
    extractor('blush', detectionCtx, cheek, 3,1, notThis);
    extractor('brows', detectionCtx, browsSearchArea, 2,1, notThis);
    extractor('eyes', detectionCtx, eyes, 6, 1, notThis);

    extractor('_lips', detectionCtx, lips, 5,1);
    extractor('_blush', detectionCtx, cheek, 3,1);
    extractor('_brows', detectionCtx, browsSearchArea, 2,1);
    extractor('_eyes', detectionCtx, eyes, 6, 1);
  }
  document.getElementById("loading").classList.add("d-none"); // make loading gif disappear
  document.getElementById("color_matching_products-container").style.display = 'block';
  document.getElementById("color_results_holder").style.visibility = 'visible';


}

function matchingProductsFormat(product, index) {
  // If the variants doesn't have Image src
  var out_put = "";
  out_put = `<div id="color_matching_${product.pid}" class="grid__item grid-product small--one-half cd-medium-up--one-third grid-product__has-quick-shop aos-init aos-animate" data-aos="row-of-3">
          <div class="grid-product__content">
            <a class="grid-product__link " href="/products/${product.p.handle}?variant=${product.vid}" target="_blank">
              <div class="grid-product__image-mask">
                <div class="grid__image-ratio grid__image-ratio--portrait lazyloaded" data-bgset="${product.img}" style="background-image: url(${product.img});"">
                </div>
              </div>
              <div class="grid-product__meta">
                <div class="grid-product__title grid-product__title--body">${product.title}</div>
                <div class="grid-product__vendor">${product.p.vendor}</div>
                <div class="grid-product__price">$${product.v.price}
                </div>
              </div>
            </a>
            <!--  ============= add custom button ( quick view, love, add to cart ) =============-->
            <div class="quick-product__menus quick-product__btn cssgrid w-100">
              <!--   add wishlist -->
              <div class="d-flex quick-product__icon-bg">
                <div class="ssw-faveiticon sswfaveicon${product.pid}">
                  <i data-product-id="${product.pid}" data-count="0" class="ssw-icon-heart-o ssw-fave-icon ssw-wishlist-element ssw-not-synch" title="{{ 'socialshopwave.fave' | t }}" data-params="{'product_id':'${product.pid}','event':'fave_button','page':'product_profile'}"></i>
                  <span class="faves-count">...</span>
                </div>
              </div>
              <!--  end of  add wishlist -->
              <div aria-expanded class="quick-product__btn js-modal-open-quick-modal-${product.pid} d-flex quick-product__icon-bg quick-product__view" data-product-id="${product.pid}">
              <a href="/products/${product.p.handle}?variant=${product.vid}" target="_blank" class="w-100 h-100">
                <span class="quick-product__label d-flex align-self-center quick-try-on w-100 h-100"></span>
                </a>
              </div>
              <form action="/cart/add" class="d-flex quick-product__icon-bg" id="product-form-${product.pid}" method="post">
                <input name="id" type="hidden" value="${product.vid}">
                <div>
                  <button class="quick_add_cart_icon d-flex quick-product__icon-bg" name="add" type="submit">
                    <span class="quick_add_cart_icon_span"></span>
                  </button>
                </div>
              </form>
            </div>
            <!-- =============  end of custom button  =============-->
          </div>
          <div class="grid-product__colors grid-product__colors--${product.pid}">
           <div id="color_squares_container-${product.pid}" class="d-flex">
          </div>
          </div>
        </div>
    </div>`;

  return out_put;
}

function colorSquareFormat(product, color, showSameColorName) {
  var output = "";
  var count = 0;
  var LIMIT_SHOWING_COLOR_SWATCHES = 5;
  for (let i = 0; i < product.variants.length; i++) {
    const variant = product.variants[i];
    const option2_value = variant.option2;
    const option2_name = closest_color(option2_value, showSameColorName);

    if (typeof color != "string") {
      for (let i = 0; i < color.length; i++) {
        const eye_cl = color[i];
        if (eye_cl == option2_name) {
          count++;
          if (count < LIMIT_SHOWING_COLOR_SWATCHES) {
            output += `<button class="color-swatch color-swatch--small color-swatch--cabbage-rose color-swatch--with-image" data-variant-id="${variant.id}" style="background-color: ${option2_value};"></button>`;
          }
        }
      }
    } else {
      if (color == option2_name) {
        count++;
        if (count < LIMIT_SHOWING_COLOR_SWATCHES) {
          output += `<button class="color-swatch color-swatch--small color-swatch--cabbage-rose color-swatch--with-image" data-variant-id="${variant.id}" style="background-color: ${option2_value};"></button>`;
        }
      }
    }
  }

  if (count >= LIMIT_SHOWING_COLOR_SWATCHES) {
    output += ` +${count - LIMIT_SHOWING_COLOR_SWATCHES + 1}`;
  }
  return output;
}


function miloAnswer(bool) {
  var milo_answer = "";
  if (bool) {
    milo_answer =
      "Here are products matching the colours that you are looking for. Try them on!";
    document.getElementById("milo-answer-text").innerText = milo_answer;
  } else {
    milo_answer = `<button class="bg-yellow option_btn"><a href="/pages/color-detection" class="text-white">Choose another file</a></button>`;
    document.getElementById("milo-answer-text").innerHTML = milo_answer;
    document.getElementById("color_results_holder").classList.add("d-none");
  }
}

function _makeRequest(fpart, cb) {
  var xmlhttp = new XMLHttpRequest();
  var url = `/collections/cd-${fpart}-results/products.json?limit=250?page=1`;

  xmlhttp.open("GET", url, true);

  try {
    xmlhttp.send();
    xmlhttp.onreadystatechange = function() {
      if (this.readyState == 4 && this.status == 200) {
        var products = JSON.parse(this.responseText);
        cb(products);
      }
    };
  } catch (err) {
    // instead of onerror
    alert("Ajax Error. Please check your Internet connection.");
  }
}

function loadJSONcollection(fpart, colors) {//}, html_cl, showSameColorName) {
  _makeRequest(fpart, function(products) {
    colorMatchProductChecker(products, fpart, colors);
    miloAnswer(true);
  });


  function colorMatchProductChecker(res, fp, colors) {
    if(!res)
      return;
    var count;

    var b = store.sub( [ 'threshold', 'maxCount', 'maxThreshold' ], function( threshold, maxCount, maxThreshold ){

      var list = [];
      res.products.forEach( function( product ){
        product.variants.forEach( function( variant ){
          var color = variant.option2.substr( 1 ),
            r = parseInt( color[ 0 ] + color[ 1 ], 16 ),
            g = parseInt( color[ 2 ] + color[ 3 ], 16 ),
            b = parseInt( color[ 4 ] + color[ 4 ], 16 );

          list.push( {
            p: product, v: variant,
            pid: product.id,
            vid: variant.id,
            description: product.body_html,
            title: product.title,
            color: variant.option2,
            colorName: variant.option1,
            img: variant.featured_image && variant.featured_image.src || ( product.images[ 0 ] || {} ).src,
            sku: variant.option3,
            hsv: rgbToLab( r, g, b )
          } );
        } );
      } );
      var used = {};
      var all = [].concat.apply( [],
        colors.map( function( clr ){
          var epsilon = threshold;
          var matched = list.map( function( i ){
            return { i: i, d: labDistance( i.hsv, clr.hsv ), c: clr };
          } )
            .filter( function( i ){
              return i.d <= maxThreshold;
            } )
            .sort( function( a, b ){
              return a.d - b.d;
            } );
          var allMatched = matched.slice();
          if( maxCount === 0 )
            return matched;

          matched = allMatched.filter( function( a ){
            return a.d <= threshold;
          } );

          var lastMatched = matched;
          var m = 0, step = 0;
          while( matched.length < maxCount ){
            step++;
            epsilon = epsilon + 0.25;

            if( epsilon > maxThreshold )
              break;

            if( m * step / 5 + epsilon > maxThreshold )
              break;

            if( matched.length && epsilon > ( threshold + maxThreshold ) / 2 )
              break;

            matched = allMatched.filter( function( i ){
              return i.d <= epsilon;
            } );

            m = Math.max( m, matched.length );

            lastMatched = matched;
          }
          /*if(!matched.length>3){
            matched = matched.f;
            return matched;
          }*/
          /*if(matched[0].d<0.02){
            return matched.slice( 0, 1 )
          }else{
            return matched.slice(0, 2);
          }*/
          return matched.slice( 0, maxCount );
        } ) ).filter( function( item ){
        if( !( item.i.vid in used ) ){
          used[ item.i.vid ] = true;
          return true;
        }
        return false;
      } );


      count = all.length;

      all.map( function( item ){
        document
          .getElementById( `${fp}-result` )
          .insertAdjacentHTML(
            "beforeend",
            matchingProductsFormat( item.i )
          );
      } );
    });
    binds.push(b);

    /*
    var count = 0;
    // reset
    document.getElementById(`${fp}-result`).innerHTML = "";

    for (let product_i = 0; product_i < data.products.length; product_i++) {
      const product = data.products[product_i];
      for (
        let variant_i = 0;
        variant_i < product.variants.length;
        variant_i++
      ) {
        const variant = product.variants[variant_i];
        const option2_value = variant.option2;
        const option2_name = closest_color(
          option2_value,
          showSameColorName
        );
        // if eye's color arr
        if (typeof cl != "string") {
          for (let cl_i = 0; cl_i < cl.length; cl_i++) {
            const eye_cl = cl[cl_i];
            if (eye_cl == option2_name) {
              count++;
              document
                .getElementById(`${fp}-result`)
                .insertAdjacentHTML(
                  "beforeend",
                  matchingProductsFormat(product, variant_i)
                );
              document.getElementById(
                `color_squares_container-${product.id}`
              ).innerHTML = colorSquareFormat(
                product,
                cl,
                showSameColorName
              );
              cl_i = cl.length - 1;
              variant_i = product.variants.length - 1;
            }
          }
        } else {
          if (cl == option2_name) {
            count++;
            document
              .getElementById(`${fp}-result`)
              .insertAdjacentHTML(
                "beforeend",
                matchingProductsFormat(product, variant_i)
              );
            document.getElementById(
              `color_squares_container-${product.id}`
            ).innerHTML = colorSquareFormat(
              product,
              cl,
              showSameColorName
            );
            variant_i = product.variants.length - 1;
          }
        }
      }
    }*/
    var showSameColorName = true;
    var option_button_out = "";
    var product_output = "";
    // No matching products
    json_FaceDetectionResults = count;
    if (count === 0) {
      product_output +=
        "<span style='color: darkgrey;'>no match...</span>";
      document.getElementById(`${fp}-result`).innerHTML = product_output;
    } else if (showSameColorName) {
      // show similar or close color products
      option_button_out += `<p class="milo-text text-center">Do you want to see products of close colours?
              <br>The may suit you better.</p>
            <div class="d-flex jc-sb">
              <button class="text-white bg-yellow option_btn" onclick="setJSON(false)">Yes, show me.</button>
              <button class="bg-black option_btn"><a href="/pages/color-detection" class="text-white">No, go back.</a></button>
            </div>`;
      document.getElementById(
        "cd_option_button_container"
      ).innerHTML = option_button_out;
    } else if (!showSameColorName) {
      // back to same color products result or back to initial page.
      option_button_out += `<div class="d-flex jc-sb">
              <button class="text-white bg-yellow option_btn" onclick="setJSON(true)">Back</button>
              <button class="bg-black option_btn"><a href="/pages/color-detection" class="text-white">Back to Miro</a></button>
            </div>`;
      document.getElementById(
        "cd_option_button_container"
      ).innerHTML = option_button_out;
    } else {
      return;
    }
  }
}
var json_FaceDetectionResults = false;
function setJSON(bool) {
  document.getElementById("loading").classList.add("d-none"); // make loading gif disappear
  document.getElementById("color_results_holder").classList.remove("d-none");
  // if the face detection success
  if (json_FaceDetectionResults) {
    //setResultsAndJSON(json_FaceDetectionResults, bool);
    document.getElementById("color_matching_products-container").style =
      "block";
  } else {
    // if face detection failed,
    document.getElementById("color_results_holder").classList.add("d-none");
  }
}