import { Clipboard } from '@angular/cdk/clipboard';
import { CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { inject, model, input, booleanAttribute, signal, computed, effect, untracked, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
import * as i1 from '@angular/material/icon';
import { MatIconModule } from '@angular/material/icon';
import * as i2 from '@angular/material/tooltip';
import { MatTooltipModule } from '@angular/material/tooltip';
import { DomSanitizer } from '@angular/platform-browser';
import * as Prism from 'prismjs';
import 'prismjs/components/prism-typescript';
import 'prismjs/components/prism-json';
import 'prismjs/components/prism-css';
import 'prismjs/components/prism-scss';
import { TranslatePipe } from '@sdcorejs/angular/i18n';
import 'prismjs/components/prism-markup';

class SdCodeEditor {
    #clipboard = inject(Clipboard);
    #sanitizer = inject(DomSanitizer);
    // ==========================================
    // 1. SIGNAL INPUTS & MODEL
    // ==========================================
    // Nhận bất kỳ kiểu dữ liệu nào (string, array, object)
    valueModel = model(undefined, { ...(ngDevMode ? { debugName: "valueModel" } : /* istanbul ignore next */ {}), alias: 'model' });
    language = input('typescript', ...(ngDevMode ? [{ debugName: "language" }] : /* istanbul ignore next */ []));
    maxHeight = input('500px', ...(ngDevMode ? [{ debugName: "maxHeight" }] : /* istanbul ignore next */ []));
    // Trạng thái Viewed (true = Read Only, false = Editable)
    viewed = input(false, { ...(ngDevMode ? { debugName: "viewed" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
    // ==========================================
    // 2. INTERNAL STATE
    // ==========================================
    copied = signal(false, ...(ngDevMode ? [{ debugName: "copied" }] : /* istanbul ignore next */ []));
    // Chuỗi text nội bộ dùng để map với thẻ <textarea>
    textValue = signal('', ...(ngDevMode ? [{ debugName: "textValue" }] : /* istanbul ignore next */ []));
    prismLang = computed(() => this.language() === 'html' ? 'markup' : this.language(), ...(ngDevMode ? [{ debugName: "prismLang" }] : /* istanbul ignore next */ []));
    // Cờ lưu vết để chống Loop (Vòng lặp vô tận khi bắn 2 chiều)
    _lastEmittedValue = undefined;
    constructor() {
        // ==========================================
        // EFFECT 1: Dữ liệu từ CHA truyền vào (Model -> TextValue)
        // ==========================================
        effect(() => {
            const extVal = this.valueModel();
            const lang = this.language();
            untracked(() => {
                // Nếu giá trị này do chính component bắn ra, bỏ qua để tránh loop
                if (extVal === this._lastEmittedValue)
                    return;
                if (typeof extVal === 'string') {
                    this.textValue.set(extVal);
                }
                else if (extVal !== undefined && extVal !== null) {
                    // Tự động format Object -> String nếu là JSON
                    if (lang === 'json') {
                        try {
                            this.textValue.set(JSON.stringify(extVal, null, 2));
                        }
                        catch {
                            this.textValue.set('// Lỗi: Object có tham chiếu vòng (Circular Reference)');
                        }
                    }
                    else {
                        this.textValue.set(String(extVal));
                    }
                }
                else {
                    this.textValue.set('');
                }
            });
        });
    }
    // ==========================================
    // EFFECT 2: PrismJS render (TextValue -> HTML MÀU)
    // ==========================================
    highlightedCode = computed(() => {
        // Dùng khoảng trắng để giữ độ cao cho thẻ pre nếu rỗng
        const rawCode = this.textValue() || ' ';
        const langKey = this.prismLang();
        const grammar = Prism.languages[langKey] || Prism.languages['markup'];
        // Cộng thêm \n ở cuối để chống lỗi con trỏ textarea ăn lẹm dòng cuối
        const highlightedString = Prism.highlight(rawCode, grammar, langKey) + '\n';
        return this.#sanitizer.bypassSecurityTrustHtml(highlightedString);
    }, ...(ngDevMode ? [{ debugName: "highlightedCode" }] : /* istanbul ignore next */ []));
    // ==========================================
    // EVENTS
    // ==========================================
    // Khi người dùng gõ vào Textarea (TextValue -> Model)
    onTextChange(newText) {
        this.textValue.set(newText);
        let valToEmit = newText;
        // Nếu ngôn ngữ là JSON, cố gắng trả về Object thật
        if (this.language() === 'json') {
            try {
                valToEmit = JSON.parse(newText);
            }
            catch {
                // Nếu gõ dở ngoặc/sai cú pháp -> Trả về chuỗi String tạm
                valToEmit = newText;
            }
        }
        // Ghi sổ và bắn ra ngoài
        this._lastEmittedValue = valToEmit;
        this.valueModel.set(valToEmit);
    }
    copyToClipboard() {
        const rawCode = this.textValue();
        if (!rawCode)
            return;
        if (this.#clipboard.copy(rawCode)) {
            this.copied.set(true);
            setTimeout(() => this.copied.set(false), 2000);
        }
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SdCodeEditor, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: SdCodeEditor, isStandalone: true, selector: "sd-code-editor", inputs: { valueModel: { classPropertyName: "valueModel", publicName: "model", isSignal: true, isRequired: false, transformFunction: null }, language: { classPropertyName: "language", publicName: "language", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, viewed: { classPropertyName: "viewed", publicName: "viewed", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueModel: "modelChange" }, ngImport: i0, template: "<div class=\"sd-code-wrapper\" [class.is-editable]=\"!viewed()\">\n  \n  <div class=\"sd-code-header\">\n    <div class=\"mac-dots\">\n      <span class=\"dot red\"></span>\n      <span class=\"dot yellow\"></span>\n      <span class=\"dot green\"></span>\n    </div>\n    \n    <div class=\"lang-badge\">\n      {{ language().toUpperCase() }} \n      <span style=\"opacity: 0.6; margin-left: 4px; font-weight: normal;\">\n        {{ viewed() ? '(READ ONLY)' : '(EDITING)' }}\n      </span>\n    </div>\n    \n    <button class=\"copy-btn\" [matTooltip]=\"copied() ? ('core.component.code-editor.copied' | translate) : 'Copy code'\" (click)=\"copyToClipboard()\">\n      <mat-icon [class.text-success]=\"copied()\">{{ copied() ? 'check' : 'content_copy' }}</mat-icon>\n      <span>{{ copied() ? 'Copied' : 'Copy' }}</span>\n    </button>\n  </div>\n\n  <div class=\"sd-code-content\" [style.maxHeight]=\"maxHeight()\">\n    <div class=\"editor-overlay-container\">\n      \n      @if (!viewed()) {\n        <textarea\n          class=\"code-textarea\"\n          [value]=\"textValue()\"\n          (input)=\"onTextChange($any($event.target).value)\"\n          spellcheck=\"false\"\n          autocomplete=\"off\"\n          autocorrect=\"off\"\n          autocapitalize=\"off\">\n        </textarea>\n      }\n      \n      <pre aria-hidden=\"true\" class=\"code-display\"><code [class]=\"'language-' + prismLang()\" [innerHTML]=\"highlightedCode()\"></code></pre>\n      \n    </div>\n  </div>\n</div>", styles: ["@charset \"UTF-8\";.sd-code-wrapper{background-color:#1e1e1e;border-radius:8px;overflow:hidden;box-shadow:0 4px 12px #00000026;margin:16px 0;font-family:Fira Code,Consolas,Monaco,monospace}.sd-code-wrapper .sd-code-header{display:flex;align-items:center;justify-content:space-between;background-color:#2d2d2d;padding:8px 16px;border-bottom:1px solid #404040}.sd-code-wrapper .sd-code-header .mac-dots{display:flex;gap:6px}.sd-code-wrapper .sd-code-header .mac-dots .dot{width:12px;height:12px;border-radius:50%}.sd-code-wrapper .sd-code-header .mac-dots .dot.red{background-color:#ff5f56}.sd-code-wrapper .sd-code-header .mac-dots .dot.yellow{background-color:#ffbd2e}.sd-code-wrapper .sd-code-header .mac-dots .dot.green{background-color:#27c93f}.sd-code-wrapper .sd-code-header .lang-badge{color:#858585;font-size:12px;font-weight:600;letter-spacing:.5px}.sd-code-wrapper .sd-code-header .copy-btn{display:flex;align-items:center;gap:4px;background:none;border:none;color:#ccc;cursor:pointer;font-size:13px;padding:4px 8px;border-radius:4px;transition:all .2s ease}.sd-code-wrapper .sd-code-header .copy-btn mat-icon{font-size:16px;width:16px;height:16px}.sd-code-wrapper .sd-code-header .copy-btn:hover{background-color:#404040;color:#fff}.sd-code-wrapper .sd-code-header .copy-btn .text-success{color:#27c93f!important}.sd-code-wrapper .sd-code-content{overflow-y:auto;position:relative}.sd-code-wrapper .sd-code-content::-webkit-scrollbar{width:8px;height:8px}.sd-code-wrapper .sd-code-content::-webkit-scrollbar-thumb{background:#555;border-radius:4px}.sd-code-wrapper .sd-code-content::-webkit-scrollbar-thumb:hover{background:#777}.sd-code-wrapper .sd-code-content::-webkit-scrollbar-track{background:#1e1e1e}.sd-code-wrapper .sd-code-content .editor-overlay-container{position:relative;min-height:100px}.sd-code-wrapper .sd-code-content .code-textarea,.sd-code-wrapper .sd-code-content .code-display{margin:0;padding:16px;border:0;width:100%;min-height:100%;font-family:inherit;font-size:14px;line-height:1.5;white-space:pre-wrap;word-break:break-all;tab-size:2}.sd-code-wrapper .sd-code-content .code-textarea{position:absolute;top:0;left:0;z-index:2;background:transparent!important;color:transparent!important;-webkit-text-fill-color:transparent!important;caret-color:#fff;resize:none;outline:none;overflow:hidden}.sd-code-wrapper .sd-code-content .code-display{position:relative;z-index:1;pointer-events:none}.sd-code-wrapper .sd-code-content .code-display code{color:#d4d4d4;font-family:inherit}.sd-code-wrapper .token.comment,.sd-code-wrapper .token.block-comment,.sd-code-wrapper .token.prolog,.sd-code-wrapper .token.doctype,.sd-code-wrapper .token.cdata{color:#999}.sd-code-wrapper .token.punctuation{color:#ccc}.sd-code-wrapper .token.tag,.sd-code-wrapper .token.attr-name,.sd-code-wrapper .token.namespace,.sd-code-wrapper .token.deleted{color:#e2777a}.sd-code-wrapper .token.function-name{color:#6196cc}.sd-code-wrapper .token.boolean,.sd-code-wrapper .token.number,.sd-code-wrapper .token.function{color:#f08d49}.sd-code-wrapper .token.property,.sd-code-wrapper .token.class-name,.sd-code-wrapper .token.constant,.sd-code-wrapper .token.symbol{color:#f8c555}.sd-code-wrapper .token.selector,.sd-code-wrapper .token.important,.sd-code-wrapper .token.atrule,.sd-code-wrapper .token.keyword,.sd-code-wrapper .token.builtin{color:#cc99cd}.sd-code-wrapper .token.string,.sd-code-wrapper .token.char,.sd-code-wrapper .token.attr-value,.sd-code-wrapper .token.regex,.sd-code-wrapper .token.variable{color:#7ec699}.sd-code-wrapper .token.operator,.sd-code-wrapper .token.entity,.sd-code-wrapper .token.url{color:#67cdcc}.sd-code-wrapper .token.important,.sd-code-wrapper .token.bold{font-weight:700}.sd-code-wrapper .token.italic{font-style:italic}.sd-code-wrapper .token.entity{cursor:help}.sd-code-wrapper .token.inserted{color:green}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i2.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SdCodeEditor, decorators: [{
            type: Component,
            args: [{ selector: 'sd-code-editor', standalone: true, imports: [CommonModule, MatIconModule, MatTooltipModule, TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div class=\"sd-code-wrapper\" [class.is-editable]=\"!viewed()\">\n  \n  <div class=\"sd-code-header\">\n    <div class=\"mac-dots\">\n      <span class=\"dot red\"></span>\n      <span class=\"dot yellow\"></span>\n      <span class=\"dot green\"></span>\n    </div>\n    \n    <div class=\"lang-badge\">\n      {{ language().toUpperCase() }} \n      <span style=\"opacity: 0.6; margin-left: 4px; font-weight: normal;\">\n        {{ viewed() ? '(READ ONLY)' : '(EDITING)' }}\n      </span>\n    </div>\n    \n    <button class=\"copy-btn\" [matTooltip]=\"copied() ? ('core.component.code-editor.copied' | translate) : 'Copy code'\" (click)=\"copyToClipboard()\">\n      <mat-icon [class.text-success]=\"copied()\">{{ copied() ? 'check' : 'content_copy' }}</mat-icon>\n      <span>{{ copied() ? 'Copied' : 'Copy' }}</span>\n    </button>\n  </div>\n\n  <div class=\"sd-code-content\" [style.maxHeight]=\"maxHeight()\">\n    <div class=\"editor-overlay-container\">\n      \n      @if (!viewed()) {\n        <textarea\n          class=\"code-textarea\"\n          [value]=\"textValue()\"\n          (input)=\"onTextChange($any($event.target).value)\"\n          spellcheck=\"false\"\n          autocomplete=\"off\"\n          autocorrect=\"off\"\n          autocapitalize=\"off\">\n        </textarea>\n      }\n      \n      <pre aria-hidden=\"true\" class=\"code-display\"><code [class]=\"'language-' + prismLang()\" [innerHTML]=\"highlightedCode()\"></code></pre>\n      \n    </div>\n  </div>\n</div>", styles: ["@charset \"UTF-8\";.sd-code-wrapper{background-color:#1e1e1e;border-radius:8px;overflow:hidden;box-shadow:0 4px 12px #00000026;margin:16px 0;font-family:Fira Code,Consolas,Monaco,monospace}.sd-code-wrapper .sd-code-header{display:flex;align-items:center;justify-content:space-between;background-color:#2d2d2d;padding:8px 16px;border-bottom:1px solid #404040}.sd-code-wrapper .sd-code-header .mac-dots{display:flex;gap:6px}.sd-code-wrapper .sd-code-header .mac-dots .dot{width:12px;height:12px;border-radius:50%}.sd-code-wrapper .sd-code-header .mac-dots .dot.red{background-color:#ff5f56}.sd-code-wrapper .sd-code-header .mac-dots .dot.yellow{background-color:#ffbd2e}.sd-code-wrapper .sd-code-header .mac-dots .dot.green{background-color:#27c93f}.sd-code-wrapper .sd-code-header .lang-badge{color:#858585;font-size:12px;font-weight:600;letter-spacing:.5px}.sd-code-wrapper .sd-code-header .copy-btn{display:flex;align-items:center;gap:4px;background:none;border:none;color:#ccc;cursor:pointer;font-size:13px;padding:4px 8px;border-radius:4px;transition:all .2s ease}.sd-code-wrapper .sd-code-header .copy-btn mat-icon{font-size:16px;width:16px;height:16px}.sd-code-wrapper .sd-code-header .copy-btn:hover{background-color:#404040;color:#fff}.sd-code-wrapper .sd-code-header .copy-btn .text-success{color:#27c93f!important}.sd-code-wrapper .sd-code-content{overflow-y:auto;position:relative}.sd-code-wrapper .sd-code-content::-webkit-scrollbar{width:8px;height:8px}.sd-code-wrapper .sd-code-content::-webkit-scrollbar-thumb{background:#555;border-radius:4px}.sd-code-wrapper .sd-code-content::-webkit-scrollbar-thumb:hover{background:#777}.sd-code-wrapper .sd-code-content::-webkit-scrollbar-track{background:#1e1e1e}.sd-code-wrapper .sd-code-content .editor-overlay-container{position:relative;min-height:100px}.sd-code-wrapper .sd-code-content .code-textarea,.sd-code-wrapper .sd-code-content .code-display{margin:0;padding:16px;border:0;width:100%;min-height:100%;font-family:inherit;font-size:14px;line-height:1.5;white-space:pre-wrap;word-break:break-all;tab-size:2}.sd-code-wrapper .sd-code-content .code-textarea{position:absolute;top:0;left:0;z-index:2;background:transparent!important;color:transparent!important;-webkit-text-fill-color:transparent!important;caret-color:#fff;resize:none;outline:none;overflow:hidden}.sd-code-wrapper .sd-code-content .code-display{position:relative;z-index:1;pointer-events:none}.sd-code-wrapper .sd-code-content .code-display code{color:#d4d4d4;font-family:inherit}.sd-code-wrapper .token.comment,.sd-code-wrapper .token.block-comment,.sd-code-wrapper .token.prolog,.sd-code-wrapper .token.doctype,.sd-code-wrapper .token.cdata{color:#999}.sd-code-wrapper .token.punctuation{color:#ccc}.sd-code-wrapper .token.tag,.sd-code-wrapper .token.attr-name,.sd-code-wrapper .token.namespace,.sd-code-wrapper .token.deleted{color:#e2777a}.sd-code-wrapper .token.function-name{color:#6196cc}.sd-code-wrapper .token.boolean,.sd-code-wrapper .token.number,.sd-code-wrapper .token.function{color:#f08d49}.sd-code-wrapper .token.property,.sd-code-wrapper .token.class-name,.sd-code-wrapper .token.constant,.sd-code-wrapper .token.symbol{color:#f8c555}.sd-code-wrapper .token.selector,.sd-code-wrapper .token.important,.sd-code-wrapper .token.atrule,.sd-code-wrapper .token.keyword,.sd-code-wrapper .token.builtin{color:#cc99cd}.sd-code-wrapper .token.string,.sd-code-wrapper .token.char,.sd-code-wrapper .token.attr-value,.sd-code-wrapper .token.regex,.sd-code-wrapper .token.variable{color:#7ec699}.sd-code-wrapper .token.operator,.sd-code-wrapper .token.entity,.sd-code-wrapper .token.url{color:#67cdcc}.sd-code-wrapper .token.important,.sd-code-wrapper .token.bold{font-weight:700}.sd-code-wrapper .token.italic{font-style:italic}.sd-code-wrapper .token.entity{cursor:help}.sd-code-wrapper .token.inserted{color:green}\n"] }]
        }], ctorParameters: () => [], propDecorators: { valueModel: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: false }] }, { type: i0.Output, args: ["modelChange"] }], language: [{ type: i0.Input, args: [{ isSignal: true, alias: "language", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], viewed: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewed", required: false }] }] } });

/**
 * Generated bundle index. Do not edit.
 */

export { SdCodeEditor };
//# sourceMappingURL=sdcorejs-angular-components-code-editor.mjs.map
