import {
  props,
  define,
  hasNativeShadowDomSupport,
  containsTagName,
} from '@bolt/core/utils';
import { withLitHtml, html } from '@bolt/core/renderers/renderer-lit-html';
import { ifDefined } from 'lit-html/directives/if-defined';
import path from 'path';

import classNames from 'classnames/bind';

import ratioStyles from '@bolt/components-ratio/src/ratio.scss';
import imageStyles from './image.scss';

import schema from '../image.schema.yml';

import './_image-lazy-sizes';

let cx = classNames.bind(imageStyles);

@define
class BoltImage extends withLitHtml() {
  static is = 'bolt-image';

  static props = {
    src: props.string,
    alt: props.string,
    noLazy: props.boolean,
    srcset: props.string,
    sizes: props.string,
    ratio: props.string,
    placeholderColor: props.string,
    placeholderImage: props.string,
    zoom: props.boolean,
    cover: props.boolean,
  };

  // https://github.com/WebReflection/document-register-element#upgrading-the-constructor-context
  constructor(self) {
    self = super(self);
    self.useShadow = hasNativeShadowDomSupport;
    self.schema = this.getModifiedSchema(schema);
    return self;
  }

  getModifiedSchema(schema) {
    var modifiedSchema = schema;

    // Remove "lazyload" and "useAspectRatio" from schema, does not apply to web component.
    for (let property in modifiedSchema.properties) {
      if (property === 'lazyload' || property === 'useAspectRatio') {
        delete modifiedSchema.properties[property];
      }
    }

    return modifiedSchema;
  }

  lazyloadImage(image) {
    if (!this.isLoaded) {
      // Note: This immediately unveils the image. Add intersection observer?
      lazySizes.loader.unveil(image);
      this.isLoaded = true;
    }
  }

  connecting() {
    super.connecting && super.connecting();
    while (this.firstChild) {
      this.removeChild(this.firstChild);
    }
  }

  rendered() {
    super.rendered && super.rendered();

    const lazyImage = this.shadowRoot
      ? this.shadowRoot.querySelector('.js-lazyload')
      : this.querySelector('.js-lazyload');

    if (lazyImage) {
      // lazyload sometimes doesn't work work even though `lazyImage` is there, setTimeout is a workaround
      setTimeout(() => {
        this.lazyloadImage(lazyImage);
      }, 0);
    }
  }

  render() {
    // validate the original prop data passed along -- returns back the validated data w/ added default values
    const {
      src,
      alt,
      noLazy,
      srcset,
      sizes,
      ratio,
      placeholderColor,
      placeholderImage,
      zoom,
      cover,
    } = this.validateProps(this.props);

    // negate and rename variables for readability
    const lazyload = !noLazy;

    // use ratio by default, still depends upon aspect-ratio being passed in
    let useRatio = true;
    let ratioW, ratioH;

    if (ratio === 'none') {
      useRatio = false;
    } else {
      if (ratio === 'auto') {
        // TODO: automatically get image dimensions
      } else if (ratio.indexOf(':') > -1) {
        const ratioArr = ratio.split(':');
        ratioW = ratioArr[0];
        ratioH = ratioArr[1];
      }
    }

    const _isJpg = path.extname(src) === '.jpg';
    const _canUseRatio = ratioW > 0 && ratioH > 0 && useRatio;
    // Only JPGs allowed, PNGs can have transparency and may not look right layered over placeholder
    const _canUsePlaceholder = (_canUseRatio || cover) && _isJpg;

    const classes = cx('c-bolt-image__image', {
      'c-bolt-image__lazyload': lazyload,
      'c-bolt-image__lazyload--fade': lazyload,
      'c-bolt-image__lazyload--blur': lazyload && _isJpg,
      'js-lazyload': lazyload,
      'c-bolt-image--cover': cover,
    });

    const imageElement = () => {
      if (src || srcset) {
        return html`
          <img
            class="${classes}"
            src="${lazyload ? placeholderImage : src}"
            alt="${ifDefined(alt ? alt : undefined)}"
            srcset="${ifDefined(
              !lazyload || this.isLoaded ? srcset || src : undefined,
            )}"
            data-srcset="${ifDefined(lazyload ? srcset || src : undefined)}"
            sizes="${ifDefined(!lazyload || this.isLoaded ? sizes : undefined)}"
            data-sizes="${ifDefined(lazyload ? sizes : undefined)}"
            data-zoom="${ifDefined(zoom ? src : undefined)}"
          />
        `;
      }
    };

    const placeholderImageElement = () => {
      if (_canUsePlaceholder) {
        return html`
          <img
            class="${cx('c-bolt-image__image-placeholder', {
              'c-bolt-image--cover': cover,
            })}"
            src="${placeholderImage}"
            alt="${ifDefined(alt ? alt : undefined)}"
          />
        `;
      }
    };

    // Include <noscript> for server-side rendered components
    const fallbackImageElement = () => {
      if (lazyload && src) {
        return html`
          <noscript>
            <img
              class="${cx('c-bolt-image__image')}"
              src="${src}"
              alt="${ifDefined(alt ? alt : undefined)}"
              srcset="${ifDefined(!lazyload ? srcset || src : undefined)}"
              data-srcset="${ifDefined(lazyload ? srcset || src : undefined)}"
            />
          </noscript>
        `;
      }
    };

    const imageTemplate = html`
      ${placeholderImageElement()} ${imageElement()} ${fallbackImageElement()}
    `;

    const ratioTemplate = children => {
      return html`
        <bolt-ratio
          aspect-ratio-width="${ratioW * 1}"
          aspect-ratio-height="${ratioH * 1}"
        >
          ${children}
        </bolt-ratio>
      `;
    };

    if (_canUsePlaceholder && placeholderColor) {
      this.style.backgroundColor = placeholderColor;
    }

    let renderedImage;

    if (_canUseRatio) {
      renderedImage = ratioTemplate(imageTemplate);
    } else {
      renderedImage = imageTemplate;
    }

    return html`
      ${this.addStyles([imageStyles, ratioStyles])} ${renderedImage}
    `;
  }
}

export { BoltImage };

@@ -1757,24 +1757,126 @@
 necting() %7B%0A
+    // IE fires this twice, only let it remove children once%0A    if (!this._wasInitiallyRendered) %7B%0A  
     super.co
@@ -1907,16 +1907,18 @@
 ting();%0A
+  
     whil
@@ -1941,24 +1941,26 @@
 ld) %7B%0A      
+  
 this.removeC
@@ -1982,16 +1982,24 @@
 Child);%0A
+      %7D%0A
     %7D%0A  

check if component was initially rendered before removing children, IE runs twice on background component and empties the rendered HTML