/**
 * Copyright 2026 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {LitElement, css, html, nothing} from 'lit';
import {customElement, property, state} from 'lit/decorators.js';
import {SHARED_STYLES} from '../css/shared-css.js';
import './chromedash-x-meter.js';

interface StackRankItem {
  property_name: string;
  percentage: number;
  bucket_id: number;
  obsolete?: boolean;
}

@customElement('chromedash-stack-rank')
class ChromedashStackRank extends LitElement {
  @property({type: String, attribute: false})
  type = '';
  @property({type: String, attribute: false})
  view = '';
  @property({type: Array, attribute: false})
  viewList: StackRankItem[] = [];
  @property({type: Array, attribute: false})
  tempList: StackRankItem[] = [];
  @state()
  maxPercentage = 100;
  @state()
  sortType = 'percentage';
  @state()
  sortReverse = false;
  @state()
  shouldHideObsolete = true;
  @state()
  obsoleteCount = 0;

  static get styles() {
    return [
      ...SHARED_STYLES,
      css`
        :host {
          display: block;
          flex: 1;
          padding: 1px;
        }

        .title-text {
          flex: 1;
          font-weight: 500;
        }

        li {
          padding: 5px 0;
          display: flex;
          align-items: center;
        }

        #subheader {
          font-size: 15px;
          display: flex;
          justify-content: space-between;
          align-items: center;
        }

        #dropdown-selection:hover {
          background: var(--sl-color-neutral-100);
        }

        sl-button::part(base) {
          color: #000;
        }

        li > :first-child {
          flex: 1;
          word-break: break-all;
        }

        li > :nth-child(2) {
          flex: 2;
        }

        .stack-rank-header {
          margin-bottom: 5px;
          text-align: center;
        }

        .stack-rank-item {
          border-top: var(--table-divider);
        }

        .stack-rank-item-hidden {
          display: none;
        }

        .stack-rank-item-name {
          display: grid;
          grid-template-columns: var(--icon-size) 1fr;
          grid-column-gap: 15px;
          position: relative;
          left: -20px;
        }
        .stack-rank-item-name .hash-link {
          place-self: center;
          visibility: hidden;
        }
        .stack-rank-item-name:hover .hash-link {
          visibility: visible;
        }

        .stack-rank-item-result {
          display: flex;
          align-items: center;
          gap: 15px;
          margin-right: 15px;
        }

        chromedash-x-meter {
          flex: 1;
        }

        a.icon-wrapper {
          display: flex;
          gap: 3px;
          align-items: center;
        }
        a.icon-wrapper:hover {
          text-decoration: none;
        }

        .spacer {
          visibility: hidden;
        }

        sl-skeleton {
          margin: 0;
          padding: 5px 20px;
        }

        /* On small displays, only show timeline icons (no text). */
        @media only screen and (max-width: 600px) {
          .icon-text {
            display: none;
          }

          .stack-rank-item-name {
            grid-column-gap: 5px;
          }

          .stack-rank-item-result {
            margin-right: 5px;
          }
        }
      `,
    ];
  }

  willUpdate(changedProperties) {
    if (!changedProperties.has('viewList') || !this.viewList.length) return;

    this.maxPercentage = this.viewList.reduce((accum, currVal) => {
      return Math.max(accum, currVal.percentage);
    }, 0);
    setTimeout(() => {
      this.scrollToPosition();
    }, 300);

    this.obsoleteCount = this.viewList.filter(item => item.obsolete).length;
  }

  scrollToPosition(e?) {
    let hash;
    if (e) {
      hash = e.currentTarget.getAttribute('href');
    } else if (location.hash) {
      hash = decodeURIComponent(location.hash);
    }

    if (hash) {
      const el = this.renderRoot.querySelector('.stack-rank-list ' + hash);
      el?.scrollIntoView({behavior: 'smooth'});
    }
  }

  sort(e) {
    e.preventDefault();

    const parts = e.target.dataset.order.split('-');
    this.sortType = parts[0];
    this.sortReverse = Boolean(parts[1]);

    const newViewList = [...this.viewList];
    this.viewList = sortBy_(this.sortType, this.sortReverse, newViewList);
  }

  handleChangeHideObsolete(e) {
    this.shouldHideObsolete = e.target.checked;
  }

  renderSubHeader() {
    return html`
      <div id="subheader">
        <p class="title-text">
          Showing
          <span
            >${
              this.viewList.length -
              (this.shouldHideObsolete ? this.obsoleteCount : 0)
            }</span
          >
          properties
        </p>
        <sl-checkbox
          ?checked=${this.shouldHideObsolete}
          @input=${this.handleChangeHideObsolete}
        >
          Hide obsolete
        </sl-checkbox>
        <div id="dropdown-selection">
          <sl-dropdown>
            <sl-button
              slot="trigger"
              variant="text"
              ?disabled=${!this.viewList.length}
            >
              <sl-icon name="filter-left"></sl-icon>
              SORT BY
            </sl-button>
            <sl-menu @click="${this.sort}">
              <sl-menu-item
                type="checkbox"
                ?checked=${this.sortType == 'percentage' && !this.sortReverse}
                data-order="percentage"
              >
                Most used
              </sl-menu-item>
              <sl-menu-item
                type="checkbox"
                ?checked=${this.sortType == 'percentage' && this.sortReverse}
                data-order="percentage-reverse"
              >
                Least used
              </sl-menu-item>
              <sl-menu-item
                type="checkbox"
                ?checked=${this.sortType == 'property_name' && this.sortReverse}
                data-order="property_name-reverse"
              >
                Name (A-Z)
              </sl-menu-item>
              <sl-menu-item
                type="checkbox"
                ?checked=${
                  this.sortType == 'property_name' && !this.sortReverse
                }
                data-order="property_name"
              >
                Name (Z-A)
              </sl-menu-item>
            </sl-menu>
          </sl-dropdown>
        </div>
      </div>
    `;
  }

  renderStackRank(displayedList) {
    return html`
      ${displayedList.map(
        item => html`
          <li
            class="stack-rank-item ${
              this.shouldHideObsolete && item.obsolete
                ? 'stack-rank-item-hidden'
                : ''
            }"
            id="${item.property_name}"
          >
            <div
              title="${item.property_name}. Click to deep link to this property."
            >
              <a
                class="stack-rank-item-name"
                href="#${item.property_name}"
                @click=${this.scrollToPosition}
              >
                <sl-icon
                  class="hash-link"
                  library="material"
                  name="link"
                ></sl-icon>
                <p>${item.property_name}</p>
              </a>
            </div>
            <div class="stack-rank-item-result">
              <chromedash-x-meter
                value="${item.percentage}"
                max="${this.maxPercentage}"
                href="/metrics/${this.type}/timeline/${
                  this.view
                }/${item.bucket_id}"
                title="Click to see a timeline view of this property"
              >
              </chromedash-x-meter>
              <a
                class="icon-wrapper"
                href="/metrics/${this.type}/timeline/${
                  this.view
                }/${item.bucket_id}"
                title="Click to see a timeline view of this property"
              >
                <sl-icon name="graph-up"></sl-icon>
                <p class="icon-text">Timeline</p>
              </a>
            </div>
          </li>
        `
      )}
    `;
  }

  renderSkeletons() {
    return html`${Array.from(Array(20)).map(
      () => html`
        <li class="stack-rank-item">
          <sl-skeleton effect="sheen"></sl-skeleton>
          <sl-skeleton effect="sheen"></sl-skeleton>
        </li>
      `
    )}`;
  }

  renderTemporaryRank() {
    return html`
      ${this.tempList.length ? this.renderStackRank(this.tempList) : nothing}
      ${this.renderSkeletons()}
    `;
  }

  renderStackRankList() {
    return html`
      <ol class="stack-rank-list">
        <li class="stack-rank-header">
          <p class="title-text">Property name</p>
          <div class="stack-rank-item-result">
            <p class="title-text">Percentage</p>
            <a class="icon-wrapper spacer">
              <sl-icon name="graph-up"></sl-icon>
              <p class="icon-text">Timeline</p>
            </a>
          </div>
        </li>
        ${
          this.viewList.length
            ? this.renderStackRank(this.viewList)
            : this.renderTemporaryRank()
        }
      </ol>
    `;
  }

  render() {
    return html` ${this.renderSubHeader()} ${this.renderStackRankList()} `;
  }
}

const sortBy_ = (propName, reverse, arr) => {
  const compareAsNumbers = propName === 'percentage';
  arr.sort((a, b) => {
    const propA = compareAsNumbers ? Number(a[propName]) : a[propName];
    const propB = compareAsNumbers ? Number(b[propName]) : b[propName];
    if (propA > propB) {
      return reverse ? 1 : -1;
    }
    if (propA < propB) {
      return reverse ? -1 : 1;
    }
    return 0;
  });
  return arr;
};
