import { RunOnceScheduler } from "../../../base/common/async.mjs";
import { Codicon, CSSIcon } from "../../../base/common/codicons.mjs";
import { Emitter } from "../../../base/common/event.mjs";
import { localize } from "../../../nls.mjs";
import { Extensions as Extensions$1 } from "../../jsonschemas/common/jsonContributionRegistry.mjs";
import { Registry } from "../../registry/common/platform.mjs";
import { ThemeIcon } from "./themeService.mjs";
const Extensions = {
  IconContribution: "base.contributions.icons"
};
var IconContribution;
(function(IconContribution2) {
  function getDefinition(contribution, registry) {
    let definition = contribution.defaults;
    while (ThemeIcon.isThemeIcon(definition)) {
      const c = iconRegistry.getIcon(definition.id);
      if (!c) {
        return void 0;
      }
      definition = c.defaults;
    }
    return definition;
  }
  IconContribution2.getDefinition = getDefinition;
})(IconContribution || (IconContribution = {}));
class IconRegistry {
  constructor() {
    this._onDidChange = new Emitter();
    this.onDidChange = this._onDidChange.event;
    this.iconSchema = {
      definitions: {
        icons: {
          type: "object",
          properties: {
            fontId: { type: "string", description: localize("iconDefinition.fontId", "The id of the font to use. If not set, the font that is defined first is used.") },
            fontCharacter: { type: "string", description: localize("iconDefinition.fontCharacter", "The font character associated with the icon definition.") }
          },
          additionalProperties: false,
          defaultSnippets: [{ body: { fontCharacter: "\\\\e030" } }]
        }
      },
      type: "object",
      properties: {}
    };
    this.iconReferenceSchema = { type: "string", pattern: `^${CSSIcon.iconNameExpression}$`, enum: [], enumDescriptions: [] };
    this.iconsById = {};
    this.iconFontsById = {};
  }
  registerIcon(id, defaults, description, deprecationMessage) {
    const existing = this.iconsById[id];
    if (existing) {
      if (description && !existing.description) {
        existing.description = description;
        this.iconSchema.properties[id].markdownDescription = `${description} $(${id})`;
        const enumIndex = this.iconReferenceSchema.enum.indexOf(id);
        if (enumIndex !== -1) {
          this.iconReferenceSchema.enumDescriptions[enumIndex] = description;
        }
        this._onDidChange.fire();
      }
      return existing;
    }
    let iconContribution = { id, description, defaults, deprecationMessage };
    this.iconsById[id] = iconContribution;
    let propertySchema = { $ref: "#/definitions/icons" };
    if (deprecationMessage) {
      propertySchema.deprecationMessage = deprecationMessage;
    }
    if (description) {
      propertySchema.markdownDescription = `${description}: $(${id})`;
    }
    this.iconSchema.properties[id] = propertySchema;
    this.iconReferenceSchema.enum.push(id);
    this.iconReferenceSchema.enumDescriptions.push(description || "");
    this._onDidChange.fire();
    return { id };
  }
  getIcons() {
    return Object.keys(this.iconsById).map((id) => this.iconsById[id]);
  }
  getIcon(id) {
    return this.iconsById[id];
  }
  getIconSchema() {
    return this.iconSchema;
  }
  toString() {
    const sorter = (i1, i2) => {
      return i1.id.localeCompare(i2.id);
    };
    const classNames = (i) => {
      while (ThemeIcon.isThemeIcon(i.defaults)) {
        i = this.iconsById[i.defaults.id];
      }
      return `codicon codicon-${i ? i.id : ""}`;
    };
    let reference = [];
    reference.push(`| preview     | identifier                        | default codicon ID                | description`);
    reference.push(`| ----------- | --------------------------------- | --------------------------------- | --------------------------------- |`);
    const contributions = Object.keys(this.iconsById).map((key) => this.iconsById[key]);
    for (const i of contributions.filter((i2) => !!i2.description).sort(sorter)) {
      reference.push(`|<i class="${classNames(i)}"></i>|${i.id}|${ThemeIcon.isThemeIcon(i.defaults) ? i.defaults.id : i.id}|${i.description || ""}|`);
    }
    reference.push(`| preview     | identifier                        `);
    reference.push(`| ----------- | --------------------------------- |`);
    for (const i of contributions.filter((i2) => !ThemeIcon.isThemeIcon(i2.defaults)).sort(sorter)) {
      reference.push(`|<i class="${classNames(i)}"></i>|${i.id}|`);
    }
    return reference.join("\n");
  }
}
const iconRegistry = new IconRegistry();
Registry.add(Extensions.IconContribution, iconRegistry);
function registerIcon(id, defaults, description, deprecationMessage) {
  return iconRegistry.registerIcon(id, defaults, description, deprecationMessage);
}
function getIconRegistry() {
  return iconRegistry;
}
function initialize() {
  for (const icon of Codicon.getAll()) {
    iconRegistry.registerIcon(icon.id, icon.definition, icon.description);
  }
}
initialize();
const iconsSchemaId = "vscode://schemas/icons";
let schemaRegistry = Registry.as(Extensions$1.JSONContribution);
schemaRegistry.registerSchema(iconsSchemaId, iconRegistry.getIconSchema());
const delayer = new RunOnceScheduler(() => schemaRegistry.notifySchemaChanged(iconsSchemaId), 200);
iconRegistry.onDidChange(() => {
  if (!delayer.isScheduled()) {
    delayer.schedule();
  }
});
const widgetClose = registerIcon("widget-close", Codicon.close, localize("widgetClose", "Icon for the close action in widgets."));
registerIcon("goto-previous-location", Codicon.arrowUp, localize("previousChangeIcon", "Icon for goto previous editor location."));
registerIcon("goto-next-location", Codicon.arrowDown, localize("nextChangeIcon", "Icon for goto next editor location."));
ThemeIcon.modify(Codicon.sync, "spin");
ThemeIcon.modify(Codicon.loading, "spin");
export {
  Extensions,
  IconContribution,
  getIconRegistry,
  iconsSchemaId,
  registerIcon,
  widgetClose
};
