// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import * as i18n from '../../core/i18n/i18n.js';
import type * as Protocol from '../../generated/protocol.js';

const UIStrings = {
  /**
   * @description Summary line in a tooltip explaining a CSS selector specificity.
   * @example {1} PH1
   * @example {2} PH2
   * @example {3} PH3
   */
  specificity: 'Specificity: ({PH1},{PH2},{PH3})',
  /**
   * @description Tooltip line listing the selector parts contributing to the ID-like specificity bucket.
   * @example {#main} PH1
   */
  idLikeSpecificity: '(a) ID-like: {PH1}',
  /**
   * @description Tooltip line listing the selector parts contributing to the class-like specificity bucket.
   * @example {.active, :hover} PH1
   */
  classLikeSpecificity: '(b) Class-like: {PH1}',
  /**
   * @description Tooltip line listing the selector parts contributing to the type-like specificity bucket.
   * @example {div} PH1
   */
  typeLikeSpecificity: '(c) Type-like: {PH1}',
} as const;
const str_ = i18n.i18n.registerUIStrings('panels/elements/CSSSpecificityBreakdown.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);

export interface SpecificityBreakdown {
  ids: string[];
  classes: string[];
  types: string[];
}

function formatContribution(text: string, contribution: number): string {
  return contribution > 1 ? `${text} x${contribution}` : text;
}

function formatComponentList(components: string[]): string {
  const formatter = new Intl.ListFormat(i18n.DevToolsLocale.DevToolsLocale.instance().locale, {
    style: 'long',
    type: 'conjunction',
  });
  return formatter.format(components);
}

export function getSpecificityBreakdown(specificity: Protocol.CSS.Specificity): SpecificityBreakdown {
  const ids: string[] = [];
  const classes: string[] = [];
  const types: string[] = [];

  for (const component of specificity.components ?? []) {
    if (component.a > 0) {
      ids.push(formatContribution(component.text, component.a));
    }
    if (component.b > 0) {
      classes.push(formatContribution(component.text, component.b));
    }
    if (component.c > 0) {
      types.push(formatContribution(component.text, component.c));
    }
  }

  return {ids, classes, types};
}

/**
 * Formats the specificity breakdown into a human-readable multi-line string
 * suitable for displaying in a tooltip.
 *
 * Example output for selector "div#main .active:hover":
 *   Specificity: (1,2,1)
 *   (a) ID-like: #main
 *   (b) Class-like: .active, :hover
 *   (c) Type-like: div
 */
export function formatSpecificitySummary(specificity: Protocol.CSS.Specificity): string {
  return i18nString(UIStrings.specificity, {PH1: specificity.a, PH2: specificity.b, PH3: specificity.c});
}

export function getSpecificityBreakdownLines(specificity: Protocol.CSS.Specificity): string[] {
  const breakdown = getSpecificityBreakdown(specificity);
  const lines: string[] = [];

  if (breakdown.ids.length > 0) {
    lines.push(i18nString(UIStrings.idLikeSpecificity, {PH1: formatComponentList(breakdown.ids)}));
  }
  if (breakdown.classes.length > 0) {
    lines.push(i18nString(UIStrings.classLikeSpecificity, {PH1: formatComponentList(breakdown.classes)}));
  }
  if (breakdown.types.length > 0) {
    lines.push(i18nString(UIStrings.typeLikeSpecificity, {PH1: formatComponentList(breakdown.types)}));
  }

  return lines;
}

export function formatSpecificityTooltip(specificity: Protocol.CSS.Specificity): string {
  return [formatSpecificitySummary(specificity), ...getSpecificityBreakdownLines(specificity)].join('\n');
}
