import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
import { AsyncIterableObject } from '../../../../base/common/async.js';
import { CancellationToken } from '../../../../base/common/cancellation.js';
import { Color, RGBA } from '../../../../base/common/color.js';
import { DisposableStore } from '../../../../base/common/lifecycle.js';
import { EditorOption } from '../../../common/config/editorOptions.js';
import { Range } from '../../../common/core/range.js';
import { TrackedRangeStickiness } from '../../../common/model.js';
import { getColors, getColorPresentations } from './color.js';
import { ColorDetector } from './colorDetector.js';
import { ColorPickerModel } from './colorPickerModel.js';
import { ColorPickerWidget } from './colorPickerWidget.js';
import { RenderedHoverParts, HoverAnchorType } from '../../hover/browser/hoverTypes.js';
import { IThemeService } from '../../../../platform/theme/common/themeService.service.js';
import { Dimension } from '../../../../base/browser/dom.js';
import { localizeWithPath } from '../../../../nls.js';
const _moduleId = "vs/editor/contrib/colorPicker/browser/colorHoverParticipant";
class ColorHover {
    constructor(owner, range, model, provider) {
        this.owner = owner;
        this.range = range;
        this.model = model;
        this.provider = provider;
        this.forceShowAtRange = true;
    }
    isValidForHoverAnchor(anchor) {
        return (anchor.type === HoverAnchorType.Range
            && this.range.startColumn <= anchor.range.startColumn
            && this.range.endColumn >= anchor.range.endColumn);
    }
}
let ColorHoverParticipant = class ColorHoverParticipant {
    constructor(_editor, _themeService) {
        this._editor = _editor;
        this._themeService = _themeService;
        this.hoverOrdinal = 2;
    }
    computeSync(_anchor, _lineDecorations) {
        return [];
    }
    computeAsync(anchor, lineDecorations, token) {
        return AsyncIterableObject.fromPromise(this._computeAsync(anchor, lineDecorations, token));
    }
    async _computeAsync(_anchor, lineDecorations, _token) {
        if (!this._editor.hasModel()) {
            return [];
        }
        const colorDetector = ColorDetector.get(this._editor);
        if (!colorDetector) {
            return [];
        }
        for (const d of lineDecorations) {
            if (!colorDetector.isColorDecoration(d)) {
                continue;
            }
            const colorData = colorDetector.getColorData(d.range.getStartPosition());
            if (colorData) {
                const colorHover = await _createColorHover(this, this._editor.getModel(), colorData.colorInfo, colorData.provider);
                return [colorHover];
            }
        }
        return [];
    }
    renderHoverParts(context, hoverParts) {
        const renderedPart = renderHoverParts(this, this._editor, this._themeService, hoverParts, context);
        if (!renderedPart) {
            return (
                 (new RenderedHoverParts([]))
            );
        }
        this._colorPicker = renderedPart.colorPicker;
        const renderedHoverPart = {
            hoverPart: renderedPart.hoverPart,
            hoverElement: this._colorPicker.domNode,
            dispose() { renderedPart.disposables.dispose(); }
        };
        return (
             (new RenderedHoverParts([renderedHoverPart]))
        );
    }
    getAccessibleContent(hoverPart) {
        return ( localizeWithPath(_moduleId, 0, 'There is a color picker here.'));
    }
    handleResize() {
        this._colorPicker?.layout();
    }
    isColorPickerVisible() {
        return !!this._colorPicker;
    }
};
ColorHoverParticipant = ( (__decorate([
    ( (__param(1, IThemeService)))
], ColorHoverParticipant)));
class StandaloneColorPickerHover {
    constructor(owner, range, model, provider) {
        this.owner = owner;
        this.range = range;
        this.model = model;
        this.provider = provider;
    }
}
let StandaloneColorPickerParticipant = class StandaloneColorPickerParticipant {
    constructor(_editor, _themeService) {
        this._editor = _editor;
        this._themeService = _themeService;
        this.hoverOrdinal = 2;
        this._color = null;
    }
    async createColorHover(defaultColorInfo, defaultColorProvider, colorProviderRegistry) {
        if (!this._editor.hasModel()) {
            return null;
        }
        const colorDetector = ColorDetector.get(this._editor);
        if (!colorDetector) {
            return null;
        }
        const colors = await getColors(colorProviderRegistry, this._editor.getModel(), CancellationToken.None);
        let foundColorInfo = null;
        let foundColorProvider = null;
        for (const colorData of colors) {
            const colorInfo = colorData.colorInfo;
            if (Range.containsRange(colorInfo.range, defaultColorInfo.range)) {
                foundColorInfo = colorInfo;
                foundColorProvider = colorData.provider;
            }
        }
        const colorInfo = foundColorInfo ?? defaultColorInfo;
        const colorProvider = foundColorProvider ?? defaultColorProvider;
        const foundInEditor = !!foundColorInfo;
        return { colorHover: await _createColorHover(this, this._editor.getModel(), colorInfo, colorProvider), foundInEditor: foundInEditor };
    }
    async updateEditorModel(colorHoverData) {
        if (!this._editor.hasModel()) {
            return;
        }
        const colorPickerModel = colorHoverData.model;
        let range = ( (new Range(
            colorHoverData.range.startLineNumber,
            colorHoverData.range.startColumn,
            colorHoverData.range.endLineNumber,
            colorHoverData.range.endColumn
        )));
        if (this._color) {
            await _updateColorPresentations(this._editor.getModel(), colorPickerModel, this._color, range, colorHoverData);
            range = _updateEditorModel(this._editor, range, colorPickerModel);
        }
    }
    renderHoverParts(context, hoverParts) {
        return renderHoverParts(this, this._editor, this._themeService, hoverParts, context);
    }
    set color(color) {
        this._color = color;
    }
    get color() {
        return this._color;
    }
};
StandaloneColorPickerParticipant = ( (__decorate([
    ( (__param(1, IThemeService)))
], StandaloneColorPickerParticipant)));
async function _createColorHover(participant, editorModel, colorInfo, provider) {
    const originalText = editorModel.getValueInRange(colorInfo.range);
    const { red, green, blue, alpha } = colorInfo.color;
    const rgba = ( (new RGBA(
        Math.round(red * 255),
        Math.round(green * 255),
        Math.round(blue * 255),
        alpha
    )));
    const color = ( (new Color(rgba)));
    const colorPresentations = await getColorPresentations(editorModel, colorInfo, provider, CancellationToken.None);
    const model = ( (new ColorPickerModel(color, [], 0)));
    model.colorPresentations = colorPresentations || [];
    model.guessColorPresentation(color, originalText);
    if (participant instanceof ColorHoverParticipant) {
        return (
             (new ColorHover(participant, Range.lift(colorInfo.range), model, provider))
        );
    }
    else {
        return (
             (new StandaloneColorPickerHover(participant, Range.lift(colorInfo.range), model, provider))
        );
    }
}
function renderHoverParts(participant, editor, themeService, hoverParts, context) {
    if (hoverParts.length === 0 || !editor.hasModel()) {
        return undefined;
    }
    if (context.setMinimumDimensions) {
        const minimumHeight = editor.getOption(EditorOption.lineHeight) + 8;
        context.setMinimumDimensions(( (new Dimension(302, minimumHeight))));
    }
    const disposables = ( (new DisposableStore()));
    const colorHover = hoverParts[0];
    const editorModel = editor.getModel();
    const model = colorHover.model;
    const colorPicker = disposables.add(( (new ColorPickerWidget(
        context.fragment,
        model,
        editor.getOption(EditorOption.pixelRatio),
        themeService,
        participant instanceof StandaloneColorPickerParticipant
    ))));
    let editorUpdatedByColorPicker = false;
    let range = ( (new Range(
        colorHover.range.startLineNumber,
        colorHover.range.startColumn,
        colorHover.range.endLineNumber,
        colorHover.range.endColumn
    )));
    if (participant instanceof StandaloneColorPickerParticipant) {
        const color = colorHover.model.color;
        participant.color = color;
        _updateColorPresentations(editorModel, model, color, range, colorHover);
        disposables.add(model.onColorFlushed((color) => {
            participant.color = color;
        }));
    }
    else {
        disposables.add(model.onColorFlushed(async (color) => {
            await _updateColorPresentations(editorModel, model, color, range, colorHover);
            editorUpdatedByColorPicker = true;
            range = _updateEditorModel(editor, range, model);
        }));
    }
    disposables.add(model.onDidChangeColor((color) => {
        _updateColorPresentations(editorModel, model, color, range, colorHover);
    }));
    disposables.add(editor.onDidChangeModelContent((e) => {
        if (editorUpdatedByColorPicker) {
            editorUpdatedByColorPicker = false;
        }
        else {
            context.hide();
            editor.focus();
        }
    }));
    return { hoverPart: colorHover, colorPicker, disposables };
}
function _updateEditorModel(editor, range, model) {
    const textEdits = [];
    const edit = model.presentation.textEdit ?? { range, text: model.presentation.label, forceMoveMarkers: false };
    textEdits.push(edit);
    if (model.presentation.additionalTextEdits) {
        textEdits.push(...model.presentation.additionalTextEdits);
    }
    const replaceRange = Range.lift(edit.range);
    const trackedRange = editor.getModel()._setTrackedRange(null, replaceRange, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter);
    editor.executeEdits('colorpicker', textEdits);
    editor.pushUndoStop();
    return editor.getModel()._getTrackedRange(trackedRange) ?? replaceRange;
}
async function _updateColorPresentations(editorModel, colorPickerModel, color, range, colorHover) {
    const colorPresentations = await getColorPresentations(editorModel, {
        range: range,
        color: {
            red: color.rgba.r / 255,
            green: color.rgba.g / 255,
            blue: color.rgba.b / 255,
            alpha: color.rgba.a
        }
    }, colorHover.provider, CancellationToken.None);
    colorPickerModel.colorPresentations = colorPresentations || [];
}
export { ColorHover, ColorHoverParticipant, StandaloneColorPickerHover, StandaloneColorPickerParticipant };
