/* eslint no-nested-ternary: off */
import $ from 'dom7';
import Utils from '../../utils/utils';
import Framework7Class from '../../utils/class';

class Gauge extends Framework7Class {
  constructor(app, params = {}) {
    // Extends with open/close Modal methods;
    super(app, params);

    const gauge = this;

    const defaults = Utils.extend({}, app.params.gauge);

    // Extend defaults with modules params
    gauge.useModulesParams(defaults);

    gauge.params = Utils.extend(defaults, params);

    const { el } = gauge.params;
    if (!el) return gauge;

    const $el = $(el);
    if ($el.length === 0) return gauge;

    if ($el[0].f7Gauge) return $el[0].f7Gauge;

    Utils.extend(gauge, {
      app,
      $el,
      el: $el && $el[0],
    });

    $el[0].f7Gauge = gauge;

    // Install Modules
    gauge.useModules();

    gauge.init();

    return gauge;
  }

  calcRadius() {
    const gauge = this;
    const { size, borderWidth } = gauge.params;
    return (size / 2) - (borderWidth / 2);
  }

  calcBorderLength() {
    const gauge = this;
    const radius = gauge.calcRadius();
    return 2 * Math.PI * radius;
  }

  render() {
    const gauge = this;
    if (gauge.params.render) return gauge.params.render.call(gauge, gauge);

    const {
      type,
      value,
      size,
      bgColor,
      borderBgColor,
      borderColor,
      borderWidth,
      valueText,
      valueTextColor,
      valueFontSize,
      valueFontWeight,
      labelText,
      labelTextColor,
      labelFontSize,
      labelFontWeight,
    } = gauge.params;

    const semiCircle = type === 'semicircle';
    const radius = gauge.calcRadius();
    const length = gauge.calcBorderLength();
    const progress = Math.max(Math.min(value, 1), 0);

    return `
      <svg class="gauge-svg" width="${size}px" height="${semiCircle ? size / 2 : size}px" viewBox="0 0 ${size} ${semiCircle ? size / 2 : size}">
        ${semiCircle ? `
          <path
            class="gauge-back-semi"
            d="M${size - (borderWidth / 2)},${size / 2} a1,1 0 0,0 -${size - borderWidth},0"
            stroke="${borderBgColor}"
            stroke-width="${borderWidth}"
            fill="${bgColor || 'none'}"
          />
          <path
            class="gauge-front-semi"
            d="M${size - (borderWidth / 2)},${size / 2} a1,1 0 0,0 -${size - borderWidth},0"
            stroke="${borderColor}"
            stroke-width="${borderWidth}"
            stroke-dasharray="${length / 2}"
            stroke-dashoffset="${(length / 2) * (1 + progress)}"
            fill="${borderBgColor ? 'none' : (bgColor || 'none')}"
          />
        ` : `
          ${borderBgColor ? `
            <circle
              class="gauge-back-circle"
              stroke="${borderBgColor}"
              stroke-width="${borderWidth}"
              fill="${bgColor || 'none'}"
              cx="${size / 2}"
              cy="${size / 2}"
              r="${radius}"
            ></circle>
          ` : ''}
          <circle
            class="gauge-front-circle"
            transform="${`rotate(-90 ${size / 2} ${size / 2})`}"
            stroke="${borderColor}"
            stroke-width="${borderWidth}"
            stroke-dasharray="${length}"
            stroke-dashoffset="${length * (1 - progress)}"
            fill="${borderBgColor ? 'none' : bgColor || 'none'}"
            cx="${size / 2}"
            cy="${size / 2}"
            r="${radius}"
          ></circle>
        `}
        ${valueText ? `
          <text
            class="gauge-value-text"
            x="50%"
            y="${semiCircle ? '100%' : '50%'}"
            font-weight="${valueFontWeight}"
            font-size="${valueFontSize}"
            fill="${valueTextColor}"
            dy="${semiCircle ? (labelText ? -labelFontSize - 15 : -5) : 0}"
            text-anchor="middle"
            dominant-baseline="${!semiCircle && 'middle'}"
          >${valueText}</text>
        ` : ''}
        ${labelText ? `
          <text
            class="gauge-label-text"
            x="50%"
            y="${semiCircle ? '100%' : '50%'}"
            font-weight="${labelFontWeight}"
            font-size="${labelFontSize}"
            fill="${labelTextColor}"
            dy="${semiCircle ? -5 : (valueText ? ((valueFontSize / 2) + 10) : 0)}"
            text-anchor="middle"
            dominant-baseline="${!semiCircle && 'middle'}"
          >${labelText}</text>
        ` : ''}
      </svg>
    `.trim();
  }

  update(newParams = {}) {
    const gauge = this;
    const { params, $gaugeSvgEl } = gauge;

    Object.keys(newParams).forEach((param) => {
      if (typeof newParams[param] !== 'undefined') {
        params[param] = newParams[param];
      }
    });
    if ($gaugeSvgEl.length === 0) return gauge;

    const {
      value,
      size,
      bgColor,
      borderBgColor,
      borderColor,
      borderWidth,
      valueText,
      valueTextColor,
      valueFontSize,
      valueFontWeight,
      labelText,
      labelTextColor,
      labelFontSize,
      labelFontWeight,
    } = params;

    const length = gauge.calcBorderLength();
    const progress = Math.max(Math.min(value, 1), 0);
    const radius = gauge.calcRadius();
    const semiCircle = params.type === 'semicircle';

    const svgAttrs = {
      width: `${size}px`,
      height: `${semiCircle ? size / 2 : size}px`,
      viewBox: `0 0 ${size} ${semiCircle ? size / 2 : size}`,
    };
    Object.keys(svgAttrs).forEach((attr) => {
      $gaugeSvgEl.attr(attr, svgAttrs[attr]);
    });
    if (semiCircle) {
      const backAttrs = {
        d: `M${size - (borderWidth / 2)},${size / 2} a1,1 0 0,0 -${size - borderWidth},0`,
        stroke: borderBgColor,
        'stroke-width': borderWidth,
        fill: bgColor || 'none',
      };
      const frontAttrs = {
        d: `M${size - (borderWidth / 2)},${size / 2} a1,1 0 0,0 -${size - borderWidth},0`,
        stroke: borderColor,
        'stroke-width': borderWidth,
        'stroke-dasharray': length / 2,
        'stroke-dashoffset': (length / 2) * (progress - 1),
        fill: borderBgColor ? 'none' : (bgColor || 'none'),
      };
      Object.keys(backAttrs).forEach((attr) => {
        $gaugeSvgEl.find('.gauge-back-semi').attr(attr, backAttrs[attr]);
      });
      Object.keys(frontAttrs).forEach((attr) => {
        $gaugeSvgEl.find('.gauge-front-semi').attr(attr, frontAttrs[attr]);
      });
    } else {
      const backAttrs = {
        stroke: borderBgColor,
        'stroke-width': borderWidth,
        fill: bgColor || 'none',
        cx: size / 2,
        cy: size / 2,
        r: radius,
      };
      const frontAttrs = {
        transform: `rotate(-90 ${size / 2} ${size / 2})`,
        stroke: borderColor,
        'stroke-width': borderWidth,
        'stroke-dasharray': length,
        'stroke-dashoffset': length * (1 - progress),
        fill: borderBgColor ? 'none' : bgColor || 'none',
        cx: size / 2,
        cy: size / 2,
        r: radius,
      };
      Object.keys(backAttrs).forEach((attr) => {
        $gaugeSvgEl.find('.gauge-back-circle').attr(attr, backAttrs[attr]);
      });
      Object.keys(frontAttrs).forEach((attr) => {
        $gaugeSvgEl.find('.gauge-front-circle').attr(attr, frontAttrs[attr]);
      });
    }
    if (valueText) {
      if (!$gaugeSvgEl.find('.gauge-value-text').length) {
        $gaugeSvgEl.append('<text class="gauge-value-text"></text>');
      }
      const textAttrs = {
        x: '50%',
        y: semiCircle ? '100%' : '50%',
        'font-weight': valueFontWeight,
        'font-size': valueFontSize,
        fill: valueTextColor,
        dy: semiCircle ? (labelText ? -labelFontSize - 15 : -5) : 0,
        'text-anchor': 'middle',
        'dominant-baseline': !semiCircle && 'middle',
      };
      Object.keys(textAttrs).forEach((attr) => {
        $gaugeSvgEl.find('.gauge-value-text').attr(attr, textAttrs[attr]);
      });
      $gaugeSvgEl.find('.gauge-value-text').text(valueText);
    } else {
      $gaugeSvgEl.find('.gauge-value-text').remove();
    }
    if (labelText) {
      if (!$gaugeSvgEl.find('.gauge-label-text').length) {
        $gaugeSvgEl.append('<text class="gauge-label-text"></text>');
      }
      const labelAttrs = {
        x: '50%',
        y: semiCircle ? '100%' : '50%',
        'font-weight': labelFontWeight,
        'font-size': labelFontSize,
        fill: labelTextColor,
        dy: semiCircle ? -5 : (valueText ? ((valueFontSize / 2) + 10) : 0),
        'text-anchor': 'middle',
        'dominant-baseline': !semiCircle && 'middle',
      };
      Object.keys(labelAttrs).forEach((attr) => {
        $gaugeSvgEl.find('.gauge-label-text').attr(attr, labelAttrs[attr]);
      });
      $gaugeSvgEl.find('.gauge-label-text').text(labelText);
    } else {
      $gaugeSvgEl.find('.gauge-label-text').remove();
    }
    return gauge;
  }

  init() {
    const gauge = this;
    const $gaugeSvgEl = $(gauge.render()).eq(0);
    $gaugeSvgEl.f7Gauge = gauge;
    Utils.extend(gauge, {
      $gaugeSvgEl,
      gaugeSvgEl: $gaugeSvgEl && $gaugeSvgEl[0],
    });
    gauge.$el.append($gaugeSvgEl);
    return gauge;
  }

  destroy() {
    const gauge = this;
    if (!gauge.$el || gauge.destroyed) return;
    gauge.$el.trigger('gauge:beforedestroy', gauge);
    gauge.emit('local::beforeDestroy gaugeBeforeDestroy', gauge);
    gauge.$gaugeSvgEl.remove();
    delete gauge.$el[0].f7Gauge;
    Utils.deleteProps(gauge);
    gauge.destroyed = true;
  }
}
export default Gauge;
