const LitElement =
  window.LitElement || Object.getPrototypeOf(customElements.get('home-assistant') || customElements.get('hui-view'));
const { html, css } = LitElement.prototype;
const locale = {
  da: {
    minPrice: 'Minimumspris i dag:',
    maxPrice: 'Maksimal pris i dag:',
    minPriceNextDay: 'Minimumspris i morgen:',
    maxPriceNextDay: 'Maksimal pris i morgen:',
    infoNoNextDay: 'Morgendagens data er endnu ikke tilgængelige',
    from: 'fra',
    to: 'til'
  },
  de: {
    minPrice: 'Mindestpreis heute:',
    maxPrice: 'Maximaler preis heute:',
    minPriceNextDay: 'Mindestpreis morgen:',
    maxPriceNextDay: 'Maximaler preis morgen:',
    infoNoNextDay: 'Die Daten von morgen sind noch nicht verfügbar',
    from: 'von',
    to: 'bis'
  },
  en: {
    minPrice: 'Lowest price today:',
    maxPrice: 'Highest price today:',
    minPriceNextDay: 'Lowest price tomorrow:',
    maxPriceNextDay: 'Highest price tomorrow:',
    infoNoNextDay: "Tomorrow's data is not yet available",
    from: 'from',
    to: 'to'
  },
  es: {
    minPrice: 'Precio mínimo hoy:',
    maxPrice: 'Precio máximo hoy:',
    minPriceNextDay: 'Precio mínimo mañana:',
    maxPriceNextDay: 'Precio máximo mañana:',
    infoNoNextDay: 'Los datos de mañana no están disponibles aún',
    from: 'de',
    to: 'a'
  },
  fr: {
    minPrice: "Prix minimum aujourd'hui:",
    maxPrice: "Prix maximum aujourd'hui:",
    minPriceNextDay: 'Prix minimum demain:',
    maxPriceNextDay: 'Prix maximum demain:',
    infoNoNextDay: 'Les données de demain ne sont pas encore disponibles',
    from: 'de',
    to: 'à'
  },
  nl: {
    minPrice: 'Minimumspris i dag:',
    maxPrice: 'Maksimal pris i dag:',
    minPriceNextDay: 'Minimum prijs morgen:',
    maxPriceNextDay: 'Maximale prijs morgen:',
    infoNoNextDay: 'De gegevens van morgen zijn nog niet beschikbaar',
    from: 'fra',
    to: 'til'
  },
  ru: {
    minPrice: 'Минимальная цена сегодня:',
    maxPrice: 'Максимальная цена сегодня:',
    minPriceNextDay: 'Минимальная цена завтра:',
    maxPriceNextDay: 'Максимальная цена завтра:',
    infoNoNextDay: 'Данные завтра еще не доступны',
    from: 'С',
    to: 'до'
  },
  sv: {
    minPrice: 'Lägsta pris idag:',
    maxPrice: 'Maxpris idag:',
    minPriceNextDay: 'Lägsta pris imorgon:',
    maxPriceNextDay: 'Maxpris i morgon:',
    infoNoNextDay: 'Morgondagens data är ännu inte tillgängliga',
    from: '',
    to: 'till'
  }
};
const tariffPeriodIconColors = {
  error: '--error-color',
  normal: '--warning-color',
  peak: '--error-color',
  valley: '--success-color',
  'super-valley': '--info-color'
};
const tariffPeriodIcons = {
  error:
    'M 28.342306,10.429944 27.798557,32.995546 H 24.243272 L 23.657695,10.429944 Z M 28.133172,41.570057 H 23.86683 v -4.412736 h 4.266342 z',
  normal:
    'M 31.032172,16.612305 20.999855,32.113255 15.66609,25.065424 H 0.97821381 a 25.017275,25.017275 0 0 0 -0.0332829,0.949884 25.017275,25.017275 0 0 0 0.0468985,0.940092 H 14.800215 l 6.199595,8.453119 10.03232,-15.502917 5.335714,7.049798 h 14.578421 a 25.017275,25.017275 0 0 0 0.03328,-0.940092 25.017275,25.017275 0 0 0 -0.0469,-0.949884 H 37.233737 Z',
  peak:
    'M 2.5238392,34.768609 A 25.003164,25.003164 0 0 1 1.9104804,32.879664 h 8.6436716 l 15.49805,-22.870055 15.121052,22.870055 h 8.891749 a 25.003164,25.003164 0 0 1 -0.628986,1.888945 H 40.038344 L 26.052202,13.679995 12.06606,34.768609 Z',
  valley:
    'm 2.5238392,17.238401 a 25.003164,25.003164 0 0 0 -0.6133588,1.888945 h 8.6436716 l 15.49805,22.870055 15.121052,-22.870055 h 8.891749 A 25.003164,25.003164 0 0 0 49.436017,17.238401 H 40.038344 L 26.052202,38.327015 12.06606,17.238401 Z',
  'super-valley':
    'm 30.867213,27.342466 c 0,0.670334 -0.543413,1.213747 -1.213747,1.213746 -0.670333,-10e-7 -1.213744,-0.543413 -1.213744,-1.213746 0,-0.670333 0.543411,-1.213745 1.213744,-1.213746 0.670334,-1e-6 1.213747,0.543412 1.213747,1.213746 z m -7.282476,0 c 0,0.670333 -0.543412,1.213746 -1.213745,1.213746 -0.670334,0 -1.213746,-0.543412 -1.213746,-1.213746 0,-0.670334 0.543412,-1.213746 1.213746,-1.213746 0.670333,0 1.213745,0.543413 1.213745,1.213746 z m 8.026907,-6.869803 c -0.161832,-0.477407 -0.614966,-0.817256 -1.149013,-0.817256 h -8.900804 c -0.534048,0 -0.979088,0.339849 -1.149012,0.817256 l -1.683061,4.846893 v 6.473312 c 0,0.445039 0.364123,0.809164 0.809163,0.809164 h 0.809164 c 0.445041,0 0.809165,-0.364125 0.809165,-0.809164 v -0.809165 h 9.709967 v 0.809165 c 0,0.445039 0.364125,0.809164 0.809164,0.809164 h 0.809165 c 0.445039,0 0.809163,-0.364125 0.809163,-0.809164 v -6.473312 z m -9.800018,0.767664 h 8.393115 l 0.841531,2.49431 H 20.970096 Z m 9.89816,8.158458 H 20.314672 v -3.837522 l 0.0971,-0.275116 h 11.209006 l 0.089,0.275116 z M 25.208235,17.875001 v -1.607989 h -3.215979 l 4.823966,-2.411981 v 1.607988 H 30.0322 Z M 2.5904451,17.061236 C 2.3615878,17.681074 2.1574473,18.309759 1.9785073,18.945805 H 10.602006 V 37.331696 H 41.150085 V 18.945805 h 8.871408 c -0.184075,-0.636272 -0.393416,-1.26496 -0.62753,-1.884569 H 38.720725 V 35.001194 H 12.908652 V 17.061236 Z'
};
const fireEvent = (node, type, detail, options) => {
  options = options || {};
  detail = detail === null || detail === undefined ? {} : detail;
  const event = new Event(type, {
    bubbles: options.bubbles === undefined ? true : options.bubbles,
    cancelable: Boolean(options.cancelable),
    composed: options.composed === undefined ? true : options.composed
  });
  event.detail = detail;
  node.dispatchEvent(event);
  return event;
};
function hasConfigOrEntityChanged(element, changedProps) {
  if (changedProps.has('_config')) {
    return true;
  }
  const oldHass = changedProps.get('hass');
  if (oldHass) {
    return oldHass.states[element._config.entity] !== element.hass.states[element._config.entity];
  }
  return true;
}
class PVPCHourlyPricingCard extends LitElement {
  static get properties() {
    return {
      _config: { type: Object },
      hass: { type: Object }
    };
  }
  static async getConfigElement() {
    await import('./pvpc-hourly-pricing-card-editor.js');
    return document.createElement('pvpc-hourly-pricing-card-editor');
  }
  static getStubConfig(hass, entities, entitiesFallback) {
    const entity = Object.keys(hass.states).find((eid) =>
      Object.keys(hass.states[eid].attributes).some((aid) => aid == 'min_price_at')
    );
    return { entity: entity };
  }
  setConfig(config) {
    if (!config.entity) {
      throw new Error('Please define a "Spain electricity hourly pricing (PVPC)" entity');
    }
    this._config = config;
    this.setPVPCHourlyPricingObj();
  }
  setPVPCHourlyPricingObj() {
    if (!this.hass) return;
    this.pvpcHourlyPricingObj = this._config.entity in this.hass.states ? this.hass.states[this._config.entity] : null;
    if (!this.pvpcHourlyPricingObj) return;
    this.despiction = this.getDespiction(this.pvpcHourlyPricingObj.attributes);
  }
  shouldUpdate(changedProps) {
    return hasConfigOrEntityChanged(this, changedProps);
  }
  updated(param) {
    this.setPVPCHourlyPricingObj();
    let chart = this.shadowRoot.getElementById('Chart');
    if (chart) {
      chart.data = this.ChartData;
      chart.hass = this.hass;
    }
  }
  render() {
    if (!this._config || !this.hass) {
      return html``;
    }
    this.setPVPCHourlyPricingObj();
    this.numberElements = 0;
    this.lang = this.hass.selectedLanguage || this.hass.language;
    if (!this.pvpcHourlyPricingObj) {
      return html`
        
        
          Entity not available: ${this._config.entity}
        
      `;
    }
    return html`
      
        ${this._config.current !== false ? this.renderCurrent() : ''}
        ${this._config.details !== false ? this.renderDetails() : ''}
        ${this._config.graph !== false ? this.renderGraph() : ''}
        ${this._config.info !== false ? this.renderInfo() : ''}
      
    `;
  }
  renderCurrent() {
    this.numberElements++;
    const tariffPeriod = this.getTariffPeriod(this.pvpcHourlyPricingObj.attributes.tariff);
    const style = getComputedStyle(document.body);
    const iconColor = style.getPropertyValue(tariffPeriodIconColors[tariffPeriod]);
    return html`
      
        
        ${this.getFixedFloat(this.pvpcHourlyPricingObj.state)}
         ${this.pvpcHourlyPricingObj.attributes.unit_of_measurement}
       
    `;
  }
  renderDetails() {
    if (!this.despiction) {
      return html``;
    }
    const minPrice = this.getFixedFloat(this.despiction.minPrice);
    const minPriceFrom = this.getTimeString(new Date().setHours(this.despiction.minIndex, 0));
    const minPriceTo = this.getTimeString(new Date().setHours(this.despiction.minIndex + 1, 0));
    const maxPrice = this.getFixedFloat(this.despiction.maxPrice);
    const maxPriceFrom = this.getTimeString(new Date().setHours(this.despiction.maxIndex, 0));
    const maxPriceTo = this.getTimeString(new Date().setHours(this.despiction.maxIndex + 1, 0));
    const minPriceNextDay = this.getFixedFloat(this.despiction.minPriceNextDay);
    const minPriceFromNextDay = this.getTimeString(new Date().setHours(this.despiction.minIndexNextDay, 0));
    const minPriceToNextDay = this.getTimeString(new Date().setHours(this.despiction.minIndexNextDay + 1, 0));
    const maxPriceNextDay = this.getFixedFloat(this.despiction.maxPriceNextDay);
    const maxPriceFromNextDay = this.getTimeString(new Date().setHours(this.despiction.maxIndexNextDay, 0));
    const maxPriceToNextDay = this.getTimeString(new Date().setHours(this.despiction.maxIndexNextDay + 1, 0));
    this.numberElements++;
    return html`
      
        - 
          
          ${this.ll('minPrice')} ${minPrice}${this.pvpcHourlyPricingObj.attributes.unit_of_measurement}
          ${this.ll('from')} ${minPriceFrom} ${this.ll('to')} ${minPriceTo}
        
- 
          
          ${this.ll('maxPrice')} ${maxPrice}${this.pvpcHourlyPricingObj.attributes.unit_of_measurement}
          ${this.ll('from')} ${maxPriceFrom} ${this.ll('to')} ${maxPriceTo}
        ${this.despiction.minPriceNextDay
          ? html`
- 
                
                ${this.ll('minPriceNextDay')}
                ${minPriceNextDay}${this.pvpcHourlyPricingObj.attributes.unit_of_measurement} ${this.ll('from')}
                ${minPriceFromNextDay} ${this.ll('to')} ${minPriceToNextDay}
              
- 
                
                ${this.ll('maxPriceNextDay')}
                ${maxPriceNextDay}${this.pvpcHourlyPricingObj.attributes.unit_of_measurement} ${this.ll('from')}
                ${maxPriceFromNextDay} ${this.ll('to')} ${maxPriceToNextDay}
              `
          : ''}
`;
  }
  renderGraph() {
    if (!this.despiction) {
      return html``;
    }
    this.numberElements++;
    this.drawChart();
    return html`
        
      
    `;
  }
  renderInfo() {
    if (!this.despiction) {
      return html``;
    }
    this.numberElements++;
    if (!this.despiction.minPriceNextDay) {
      return html`
        ${this.ll('infoNoNextDay')}
      `;
    } else {
      return html``;
    }
  }
  drawChart() {
    if (!this.despiction) return;
    const that = this;
    const style = getComputedStyle(document.body);
    const legendTextColor = style.getPropertyValue('--primary-text-color');
    const axisTextColor = style.getPropertyValue('--secondary-text-color');
    const dividerColor = style.getPropertyValue('--divider-color');
    const selectionColor = style.getPropertyValue('--paper-grey-500');
    const today = new Date();
    const minIndex = this.despiction.minIndex;
    const maxIndex = this.despiction.maxIndex;
    const minIndexNextDay = this.despiction.minIndexNextDay;
    const maxIndexNextDay = this.despiction.maxIndexNextDay;
    const hasNextDayData = this.despiction.pricesNextDay[0] !== undefined;
    const minIcon = '▼';
    const maxIcon = '▲';
    const chartOptions = {
      type: 'line',
      data: {
        labels: this.despiction.dateTime,
        datasets: [
          {
            label: that.getDateString(today),
            type: 'line',
            data: this.despiction.prices,
            borderWidth: 2.0,
            pointRadius: 0.0,
            pointHitRadius: 0.0,
            fill: false,
            steppedLine: true
          }
        ]
      },
      options: {
        animation: {
          duration: 300,
          easing: 'linear',
          onComplete: function () {
            const chartInstance = this.chart;
            const ctx = chartInstance.ctx;
            const fontSize = 12;
            const fontStyle = 'normal';
            const fontFamily = 'Roboto';
            ctx.font = Chart.helpers.fontString(fontSize, fontStyle, fontFamily);
            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            const meta = chartInstance.controller.getDatasetMeta(0);
            const minBarStart = meta.data[minIndex];
            const minBarEnd = meta.data[minIndex + 1];
            const pointToPointCenterXOffset = (minBarEnd._model.x - minBarStart._model.x) / 2;
            const maxBar = meta.data[maxIndex];
            const iconYOffset = 8;
            ctx.fillStyle = meta.dataset._model.borderColor;
            ctx.fillText(minIcon, minBarStart._model.x + pointToPointCenterXOffset, minBarStart._model.y - iconYOffset);
            ctx.fillText(maxIcon, maxBar._model.x + pointToPointCenterXOffset, maxBar._model.y - iconYOffset);
            ctx.save();
            const selectedIndex =
              chartInstance.tooltip._active &&
              chartInstance.tooltip._active.length > 0 &&
              chartInstance.tooltip._active[0]._index < 24
                ? chartInstance.tooltip._active[0]._index
                : today.getHours();
            const yaxis = meta.controller.chart.scales['y-axis-0'];
            const xBarStart = meta.data[selectedIndex]._model.x;
            const xBarEnd = meta.data[selectedIndex + 1]._model.x;
            const yBarStart = yaxis.top;
            const yBarEnd = yaxis.bottom;
            ctx.globalAlpha = 0.6;
            ctx.beginPath();
            ctx.moveTo(xBarStart, yBarStart);
            ctx.lineTo(xBarStart, yBarEnd);
            ctx.strokeStyle = selectionColor;
            ctx.stroke();
            ctx.beginPath();
            ctx.moveTo(xBarEnd, yBarStart);
            ctx.lineTo(xBarEnd, yBarEnd);
            ctx.strokeStyle = selectionColor;
            ctx.stroke();
            ctx.globalAlpha = 0.3;
            ctx.fillStyle = selectionColor;
            ctx.fillRect(xBarStart, yBarStart, xBarEnd - xBarStart, yBarEnd - yBarStart);
            ctx.restore();
            if (hasNextDayData) {
              const meta_next_day = chartInstance.controller.getDatasetMeta(1);
              const minNextDayBar = meta_next_day.data[minIndexNextDay];
              const maxNextDayBar = meta_next_day.data[maxIndexNextDay];
              ctx.fillStyle = meta_next_day.dataset._model.borderColor;
              ctx.fillText(
                minIcon,
                minNextDayBar._model.x + pointToPointCenterXOffset,
                minNextDayBar._model.y - iconYOffset
              );
              ctx.fillText(
                maxIcon,
                maxNextDayBar._model.x + pointToPointCenterXOffset,
                maxNextDayBar._model.y - iconYOffset
              );
            }
          }
        },
        legend: {
          display: true,
          labels: {
            fontColor: legendTextColor,
            fontSize: 14,
            usePointStyle: true,
            boxWidth: 6
          }
        },
        scales: {
          xAxes: [
            {
              type: 'time',
              maxBarThickness: 15,
              display: false,
              ticks: {
                display: false
              },
              gridLines: {
                display: false
              }
            },
            {
              position: 'bottom',
              gridLines: {
                display: true,
                drawTicks: false,
                drawBorder: false,
                color: dividerColor
              },
              ticks: {
                display: true,
                padding: 10,
                source: 'labels',
                autoSkip: true,
                fontColor: axisTextColor,
                maxRotation: 0,
                callback: function (value, index, values) {
                  return that.getHourString.call(that, value);
                }
              }
            }
          ],
          yAxes: [
            {
              position: 'left',
              gridLines: {
                display: true,
                drawBorder: false,
                drawTicks: false,
                color: dividerColor,
                borderDash: [4, 6]
              },
              ticks: {
                display: true,
                padding: 10,
                fontColor: axisTextColor
              }
            }
          ]
        },
        tooltips: {
          mode: 'index',
          intersect: false,
          callbacks: {
            title: function (items, data) {
              const index = items[0].index != 24 ? items[0].index : (items[0].index = 23);
              const date = new Date(data.labels[index]);
              const initDate = that.getTimeString(date);
              const endDate = that.getTimeString(date.setHours(date.getHours() + 1));
              return initDate + ' - ' + endDate;
            },
            label: function (tooltipItems, data) {
              let icon;
              const index = tooltipItems.index != 24 ? tooltipItems.index : (tooltipItems.index = 23);
              if (tooltipItems.datasetIndex === 0) {
                if (index == minIndex) {
                  icon = minIcon;
                } else if (index == maxIndex) {
                  icon = maxIcon;
                }
              } else if (tooltipItems.datasetIndex === 1) {
                if (index == minIndexNextDay) {
                  icon = minIcon;
                } else if (index == maxIndexNextDay) {
                  icon = maxIcon;
                }
              }
              const labelTitle = data.datasets[tooltipItems.datasetIndex].label || '';
              const label =
                labelTitle +
                ': ' +
                parseFloat(tooltipItems.value).toFixed(5) +
                ' ' +
                that.pvpcHourlyPricingObj.attributes.unit_of_measurement +
                ' ';
              return icon ? label + icon : label;
            }
          }
        }
      }
    };
    if (hasNextDayData) {
      chartOptions.data.datasets.push({
        label: that.getDateString(today.setDate(today.getDate() + 1)),
        type: 'line',
        data: this.despiction.pricesNextDay,
        borderWidth: 2.0,
        pointRadius: 0.0,
        pointHitRadius: 0.0,
        fill: false,
        steppedLine: true
      });
    }
    this.ChartData = chartOptions;
  }
  getDespiction(attributes) {
    const priceRegex = /price_\d\dh/;
    const priceNextDayRegex = /price_(next|last)_day_\d\dh/;
    const priceArray = Object.keys(attributes)
      .filter((key) => priceRegex.test(key))
      .map((key) => attributes[key]);
    const priceNextDayArray = Object.keys(attributes)
      .filter((key) => priceNextDayRegex.test(key))
      .map((key) => attributes[key]);
    let data = [];
    let dateTime = [];
    let prices = [];
    let pricesNextDay = [];
    for (let index = 0; index < 24; index++) {
      dateTime.push(new Date().setHours(index, 0));
      prices.push(priceArray[index]);
      pricesNextDay.push(priceNextDayArray[index]);
    }
    dateTime.push(new Date().setHours(24, 0));
    prices.push(priceArray[23]);
    pricesNextDay.push(priceNextDayArray[23]);
    data.dateTime = dateTime;
    data.prices = prices;
    data.pricesNextDay = pricesNextDay;
    data.minPrice = Math.min.apply(null, prices);
    data.maxPrice = Math.max.apply(null, prices);
    data.minIndex = prices.indexOf(data.minPrice);
    data.maxIndex = prices.indexOf(data.maxPrice);
    data.minPriceNextDay = Math.min.apply(null, pricesNextDay);
    data.maxPriceNextDay = Math.max.apply(null, pricesNextDay);
    data.minIndexNextDay = pricesNextDay.indexOf(data.minPriceNextDay);
    data.maxIndexNextDay = pricesNextDay.indexOf(data.maxPriceNextDay);
    return data;
  }
  getTariffPeriod(tariff) {
    let period;
    switch (tariff) {
      case 'normal':
        period = 'normal';
        break;
      case 'discrimination':
        const utcHours = new Date().getUTCHours();
        if (utcHours >= 21 || utcHours < 11) {
          period = 'valley';
        } else {
          period = 'peak';
        }
        break;
      case 'electric_car':
        const hours = new Date().getHours();
        if (hours >= 1 && hours < 7) {
          period = 'super-valley';
        } else if (hours >= 13 && hours < 23) {
          period = 'peak';
        } else {
          period = 'valley';
        }
        break;
      default:
        period = 'error';
    }
    return period;
  }
  getDateString(datetime) {
    return new Date(datetime).toLocaleDateString(this.lang, {
      day: '2-digit',
      month: '2-digit',
      year: 'numeric'
    });
  }
  getHourString(datetime) {
    return new Date(datetime).toLocaleTimeString(this.lang, { hour: '2-digit', hour12: false });
  }
  getTimeString(datetime) {
    return new Date(datetime).toLocaleTimeString(this.lang, { hour: '2-digit', minute: '2-digit', hour12: false });
  }
  getFixedFloat(number) {
    return parseFloat(number).toFixed(5);
  }
  _handleClick() {
    fireEvent(this, 'hass-more-info', { entityId: this._config.entity });
  }
  getCardSize() {
    return this.numberElements || 3;
  }
  static get styles() {
    return css`
      ha-card {
        margin: auto;
        padding-top: 1.3em;
        padding-bottom: 1.3em;
        padding-left: 1em;
        padding-right: 1em;
        position: relative;
      }
      ha-icon {
        color: var(--paper-item-icon-color);
      }
      .spacer {
        padding-top: 1em;
      }
      .clear {
        clear: both;
      }
      .tappable {
        cursor: pointer;
      }
      .current {
        height: 5.5em;
        position: relative;
        display: flex;
        align-items: center;
        justify-content: space-between;
      }
      .period-icon {
        padding-left: 16px;
        padding-right: 16px;
        width: 5.5em;
        height: 5.5em;
      }
      .currentPrice {
        font-weight: 300;
        font-size: 4em;
        color: var(--primary-text-color);
        margin-top: 0.5em;
        margin-right: 8px;
      }
      .currentPriceUnit {
        font-weight: 300;
        font-size: 1.5em;
        vertical-align: super;
        color: var(--primary-text-color);
        right: 0em;
        top: 0em;
        position: absolute;
        margin-right: 8px;
      }
      .details {
        font-weight: 300;
        color: var(--primary-text-color);
        list-style: none;
        padding-right: 1em;
        padding-left: 1em;
      }
      .details li {
        display: flex;
        align-items: center;
        justify-content: flex-start;
      }
      .details ha-icon {
        height: 22px;
        margin-right: 4px;
      }
      .info {
        color: var(--primary-text-color);
        text-align: center;
        padding-right: 1em;
        padding-left: 1em;
      }
    `;
  }
  ll(str) {
    if (locale[this.lang] === undefined) return locale.en[str];
    return locale[this.lang][str];
  }
}
customElements.define('pvpc-hourly-pricing-card', PVPCHourlyPricingCard);