/**
 * @fileoverview Classify · Taxonomy Governance tab.
 *
 * Self-contained sub-page: owns its header-interior (sub-tab nav + Refresh),
 * the five governance sub-tabs (Tree, Duplicates, Orphans, Treemap, Audit), and
 * the five governance dialogs (Split, Move, Merge-Into, Create-Tag, Confirm).
 *
 * Loads its own taxonomy data (Tags, Tagged Items, Tag Audit Logs, and per-tag
 * SQL aggregates) via `RunView.FromMetadataProvider(this.ProviderToUse)` /
 * `RunQuery`, exactly as the host did. Receives the already-loaded shared
 * `MJ: Content Item Tags` rows from the host via `[ContentTags]` (used for
 * per-tag counts + recent-item previews). After a governance mutation it
 * reloads its own data and emits `(DataChanged)` so the host can react if needed.
 */
import { EventEmitter, OnInit } from '@angular/core';
import { MJTagEntity, MJTagScopeEntity, MJTagSynonymEntity } from '@memberjunction/core-entities';
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
import { TabConfig } from '@memberjunction/ng-ui-components';
import { TaxonomySubTab, TaxTreeNode, TaxDuplicatePair, TaxOrphanCard, TaxTreemapCell, TaxAuditEvent, TaxHealthStat } from '../shared/classify.types';
import * as i0 from "@angular/core";
export declare class ClassifyTaxonomyTabComponent extends BaseAngularComponent implements OnInit {
    private cdr;
    /** Shared raw `MJ: Content Item Tags` rows, supplied by the host orchestrator. */
    private _contentTags;
    set ContentTags(value: Record<string, unknown>[]);
    get ContentTags(): Record<string, unknown>[];
    /** Fired after a governance mutation so the host can refresh its own surfaces if needed. */
    DataChanged: EventEmitter<void>;
    TaxSubTab: TaxonomySubTab;
    TaxTreeNodes: TaxTreeNode[];
    TaxFlatNodes: TaxTreeNode[];
    TaxFilteredNodes: TaxTreeNode[];
    TaxSelectedNode: TaxTreeNode | null;
    TaxTreeSearch: string;
    TaxDuplicates: TaxDuplicatePair[];
    TaxOrphans: TaxOrphanCard[];
    TaxAllOrphansSelected: boolean;
    TaxTreemapCells: TaxTreemapCell[];
    TaxAuditEvents: TaxAuditEvent[];
    TaxAuditFilterTypes: Set<string>;
    TaxHealth: TaxHealthStat;
    TaxRecentItems: {
        Name: string;
        Weight: number;
        Date: string;
        Icon: string;
    }[];
    TaxTreemapKPIs: {
        Label: string;
        Value: string;
    }[];
    TaxIsEditing: boolean;
    ShowCreateTagDialog: boolean;
    CreateTagName: string;
    CreateTagDescription: string;
    CreateTagParentID: string | null;
    /** Label shown in the create dialog to indicate context (e.g., "under AI Agent") */
    CreateTagParentLabel: string;
    TaxMultiSelectMode: boolean;
    TaxSelectedIDs: Set<string>;
    /** The node currently being dragged over (drop target highlight) */
    TaxDragOverNodeID: string | null;
    /** True while a drag-reparent operation is saving */
    TaxTreeSaving: boolean;
    /** Count of high-confidence duplicate pairs (>85% similarity) */
    get TaxHighConfidenceDupeCount(): number;
    /** Count of moderate-confidence duplicate pairs (70-85% similarity) */
    get TaxModerateDupeCount(): number;
    TaxEditName: string;
    TaxEditDescription: string;
    /** Active sub-tab in the selected-node editor. Only visible when a node is selected. */
    TagEditorSubTab: 'overview' | 'governance' | 'synonyms' | 'scope';
    /** The strongly-typed MJ: Tags entity backing the governance editor for the selected node. */
    GovernanceTag: MJTagEntity | null;
    /** True while the governance entity is loading. */
    GovernanceLoading: boolean;
    /** True while a governance save is in flight. */
    GovernanceSaving: boolean;
    /** Editable copies of the governance flags so we don't mutate the entity until Save(). */
    GovIsFrozen: boolean;
    GovAllowAutoGrow: boolean;
    GovRequiresReview: boolean;
    GovMaxChildren: number | null;
    GovMaxDescendantDepth: number | null;
    GovMinWeight: number | null;
    /** Synonyms for the selected tag (typed entity objects, loaded lazily per-tag). */
    Synonyms: MJTagSynonymEntity[];
    /** True while synonyms are loading. */
    SynonymsLoading: boolean;
    /** New synonym text to add. */
    NewSynonymText: string;
    /** True while a synonym add/delete is in flight. */
    SynonymSaving: boolean;
    /** Scopes for the selected tag (typed entity objects, loaded lazily per-tag). */
    Scopes: MJTagScopeEntity[];
    /** True while scopes are loading. */
    ScopesLoading: boolean;
    /** True while a scope/global mutation is in flight. */
    ScopeSaving: boolean;
    /** Selected entity ID for the "Add scope" affordance. */
    NewScopeEntityID: string | null;
    /** RecordID text for the "Add scope" affordance. */
    NewScopeRecordID: string;
    private tagsRaw;
    private taggedItemsRaw;
    private tagAuditLogsRaw;
    /** Cached per-tag aggregates from server-side SQL (weights + counts) */
    private tagAggregateWeights;
    private tagAggregateCounts;
    /** Whether a generic confirmation overlay is visible */
    ShowConfirmDialog: boolean;
    /** Title text for the confirmation dialog */
    ConfirmDialogTitle: string;
    /** Body message for the confirmation dialog */
    ConfirmDialogMessage: string;
    /** Callback invoked when user confirms */
    private confirmDialogAction;
    /** Whether the split-tag dialog is visible */
    ShowSplitDialog: boolean;
    /** Comma-separated new child tag names for the split operation */
    SplitChildNames: string;
    /** The node currently being split */
    private splitTargetNode;
    /** Whether the move-tag dialog is visible */
    ShowMoveDialog: boolean;
    /** Selected new parent tag ID for the move operation */
    MoveNewParentID: string | null;
    /** The node currently being moved */
    private moveTargetNode;
    ShowMergeIntoDialog: boolean;
    MergeSourceTag: TaxTreeNode | null;
    MergeTargetID: string | null;
    MergeTargetData: {
        ID: string;
        Label: string;
    }[];
    /** Whether the treemap drill-in panel is visible */
    ShowTreemapDrillIn: boolean;
    /** Tag node currently displayed in treemap drill-in */
    TreemapDrillInNode: TaxTreeNode | null;
    IsMerging: boolean;
    /** Subtitle rendered in the per-section `<mj-page-header-interior>`. */
    get Subtitle(): string;
    ngOnInit(): Promise<void>;
    /** Taxonomy sub-tabs as `TabConfig[]` for `<mj-tab-nav>`. */
    get taxSubTabsConfig(): TabConfig[];
    /** Adapter for `<mj-tab-nav>`'s string-typed `(TabChange)` output. */
    onTaxSubTabChange(key: string): void;
    SwitchTaxSubTab(sub: TaxonomySubTab): void;
    /**
     * Loads all data needed by the Taxonomy Governance sub-tabs:
     * Tags, Tagged Items, Tag Audit Logs, and cross-references content item tags.
     */
    private loadTaxonomyData;
    /**
     * Builds the taxonomy tree from raw tag data, wiring up parent-child
     * relationships and attaching item counts and average weights.
     */
    private buildTaxTree;
    private computeTreeDepths;
    private propagateItemCounts;
    private sortTreeNodes;
    private flattenTree;
    private computeTagHealth;
    /**
     * Counts the number of items referencing each tag, combining both
     * Tagged Items and Content Item Tags. Uses NormalizeUUID for
     * cross-platform UUID case consistency.
     */
    private countItemsByTag;
    /**
     * Loads per-tag average weights and item counts via the "Tag Aggregates" saved query.
     * This runs a SQL GROUP BY on the server, avoiding loading 17K+ TaggedItem rows to the browser.
     */
    private loadTagAggregates;
    ToggleTaxNode(node: TaxTreeNode): void;
    SelectTaxNode(node: TaxTreeNode): void;
    /**
     * Clears the lazily-loaded governance/synonyms/scope panel state so a newly
     * selected node starts fresh. Data is re-fetched on demand when its sub-tab opens.
     */
    private resetEditorPanels;
    FilterTaxTree(): void;
    private applyTaxTreeFilter;
    GetTaxBreadcrumb(node: TaxTreeNode): {
        ID: string;
        Name: string;
    }[];
    NavigateToBreadcrumb(tagId: string): void;
    private loadRecentItemsForTag;
    /**
     * Switches the selected-node editor sub-tab and lazy-loads the data for
     * the newly opened sub-tab if it hasn't been fetched yet for this node.
     */
    SwitchTagEditorSubTab(sub: 'overview' | 'governance' | 'synonyms' | 'scope'): void;
    /** Loads the data backing the currently active editor sub-tab on demand. */
    private ensureEditorSubTabLoaded;
    /** Lazy-loads the strongly-typed MJ: Tags entity for the selected node. */
    private loadGovernanceTag;
    /** Copies governance flags from the entity into the editable view fields. */
    private syncGovernanceFromEntity;
    /** A one-line subtree-impact hint derived from the selected tree node. */
    get GovernanceImpactHint(): string;
    /** Resets the governance editor fields back to the loaded entity values. */
    ResetGovernance(): void;
    /** Persists the edited governance flags to the MJ: Tags entity. */
    SaveGovernance(): Promise<void>;
    /** Lazy-loads MJ: Tag Synonyms rows for the selected tag. */
    private loadSynonyms;
    /** Returns a colored-pill CSS class for a synonym Source. */
    GetSynonymSourceClass(source: string): string;
    /** Creates a new Manual synonym for the selected tag. */
    AddSynonym(): Promise<void>;
    /** Deletes a synonym row. */
    DeleteSynonym(syn: MJTagSynonymEntity): Promise<void>;
    /** Count of synonyms awaiting review (Source = LLM/Imported, Status = Pending). */
    get PendingSynonymCount(): number;
    /** Approves a pending (machine-proposed) synonym so it begins resolving to its tag. */
    ApproveSynonym(syn: MJTagSynonymEntity): Promise<void>;
    /** Rejects a pending synonym; retained for audit and to suppress re-proposal. */
    RejectSynonym(syn: MJTagSynonymEntity): Promise<void>;
    /** Shared transition for approve/reject of a synonym's Status. */
    private setSynonymStatus;
    /** Entity options for the "Add scope" combobox, sorted by name. */
    get ScopeEntityOptions(): {
        ID: string;
        Name: string;
    }[];
    /** Whether the selected tag is global (read from the governance entity). */
    get IsTagGlobal(): boolean;
    /** Lazy-loads MJ: Tag Scopes rows for the selected tag. */
    private loadScopes;
    /** Adapter for the entity combobox's string-typed value output. */
    OnScopeEntitySelected(value: unknown): void;
    /** Toggles the tag's IsGlobal flag and persists it. */
    ToggleTagGlobal(value: boolean): Promise<void>;
    /** Creates a new MJ: Tag Scopes row for the selected tag. */
    AddScope(): Promise<void>;
    /** Deletes a scope row. */
    DeleteScope(scope: MJTagScopeEntity): Promise<void>;
    StartEditTag(): void;
    CancelEditTag(): void;
    SaveEditTag(): Promise<void>;
    MoveTag(node: TaxTreeNode, newParentId: string | null): Promise<void>;
    DeleteTag(node: TaxTreeNode): void;
    /** Open create tag dialog for a root-level tag */
    OpenCreateRootTag(): void;
    /** Open create tag dialog as child of the selected node */
    OpenCreateChildTag(): void;
    /** Open create tag dialog as child of a specific node */
    OpenCreateChildTagFor(node: TaxTreeNode): void;
    /** Close create tag dialog */
    CloseCreateTagDialog(): void;
    /** Save the new tag */
    SaveNewTag(): Promise<void>;
    /** Toggle multi-select mode on/off */
    ToggleMultiSelectMode(): void;
    /** Toggle a node's selection in multi-select mode */
    ToggleNodeSelection(node: TaxTreeNode, event: Event): void;
    /** Check if a node is selected in multi-select mode */
    IsNodeMultiSelected(nodeID: string): boolean;
    /** Handle drag start on a tree node */
    OnTreeNodeDragStart(event: DragEvent, node: TaxTreeNode): void;
    /** Handle drag over a tree node (drop target) */
    OnTreeNodeDragOver(event: DragEvent, node: TaxTreeNode): void;
    /** Handle drag leave */
    OnTreeNodeDragLeave(): void;
    /** Handle drop — reparent dragged node(s) under the drop target */
    OnTreeNodeDrop(event: DragEvent, targetNode: TaxTreeNode): Promise<void>;
    /** Handle drop on the "Root" drop zone (make root-level) */
    OnDropToRoot(event: DragEvent): Promise<void>;
    MergeTags(sourceTagId: string, targetTagId: string, sourceName: string, targetName: string): Promise<void>;
    MakeChildTag(childTagId: string, parentTagId: string): Promise<void>;
    DismissDuplicate(pair: TaxDuplicatePair): void;
    private buildTaxDuplicates;
    /** Group tags by case-insensitive name, returning only groups with 2+ members */
    private groupExactNameDuplicates;
    /**
     * Enhanced string similarity: separator normalization, abbreviation,
     * pluralization, token-overlap Jaccard, containment, and Levenshtein.
     * Returns the highest score among all heuristics.
     */
    private computeStringSimilarity;
    /** Scores simple English pluralization differences */
    private computePluralizationScore;
    /** Jaccard similarity on word tokens */
    private computeTokenJaccardSimilarity;
    private isAbbreviationOf;
    private levenshteinDistance;
    /**
     * Finds orphan tags: no parent, no children, and zero usage.
     * A tag with even 1 connection is not orphaned — it's just a leaf.
     * Uses NormalizeUUID for consistent cross-platform UUID comparisons.
     */
    private buildTaxOrphans;
    ToggleOrphanSelection(orphan: TaxOrphanCard): void;
    ToggleAllOrphans(): void;
    /**
     * Clean up TagCoOccurrence records that reference a tag before deleting it.
     * Without this, the FK constraint on TagCoOccurrence blocks the delete.
     */
    private cleanupTagReferences;
    DeleteOrphan(orphan: TaxOrphanCard): void;
    BulkDeleteOrphans(): void;
    /** Delete all orphan tags at once with a styled confirmation dialog */
    DeleteAllOrphans(): void;
    private buildTaxTreemap;
    /**
     * Builds the audit timeline from the MJ: Tag Audit Logs entity.
     * Falls back to synthesizing "created" events from tag creation dates
     * if no real audit log records exist yet.
     */
    private buildTaxAuditLog;
    /**
     * Maps real Tag Audit Log records into TaxAuditEvent objects.
     * Uses the view's denormalized Tag, PerformedByUser, and RelatedTag fields.
     */
    private buildAuditEventsFromLogs;
    /**
     * Synthesizes audit events from tag __mj_CreatedAt dates when no
     * real audit log records exist. Used as a fallback only.
     */
    private synthesizeAuditEventsFromTags;
    /**
     * Maps a PascalCase DB Action value (e.g. "Renamed") to the lowercase
     * TaxAuditAction type used in the UI. Returns null for unrecognized values.
     */
    private mapAuditActionToType;
    /**
     * Safely parses the JSON Details column from a Tag Audit Log record.
     * Returns an empty object on parse failure.
     */
    private parseAuditDetails;
    /**
     * Builds a human-readable description for an audit event based on the
     * action type and any additional context from the related tag or details JSON.
     */
    private buildAuditDescription;
    /**
     * Adds a local-only audit entry to the top of the timeline for
     * immediate UI feedback after a user action (merge, delete, etc.).
     */
    private addTaxAuditEntry;
    ToggleTaxAuditFilter(type: string): void;
    GetFilteredAuditEvents(): TaxAuditEvent[];
    private formatDayHeader;
    private buildTaxHealth;
    /** Returns the Font Awesome icon class for an audit event action type. */
    GetTaxAuditIcon(type: string): string;
    /** Opens a styled confirmation dialog, replacing browser `confirm()`. */
    OpenConfirmDialog(title: string, message: string, action: () => Promise<void>): void;
    /** User confirmed the dialog action */
    ConfirmDialogAccept(): Promise<void>;
    /** User cancelled the confirmation dialog */
    ConfirmDialogCancel(): void;
    /** Opens the split-tag dialog for a given tree node */
    OpenSplitDialog(node: TaxTreeNode): void;
    /** Closes the split-tag dialog without action */
    CloseSplitDialog(): void;
    /** Executes the split operation, creating child tags from comma-separated names */
    ExecuteSplit(): Promise<void>;
    /** Opens the move-tag dialog for a given tree node */
    OpenMoveDialog(node: TaxTreeNode): void;
    /** Closes the move-tag dialog without action */
    CloseMoveDialog(): void;
    /** Returns flat list of tags eligible as move targets (excludes the node being moved and its descendants) */
    GetMoveTargetOptions(): {
        ID: string;
        Name: string;
        Depth: number;
    }[];
    /** Collects IDs of all descendants of a node */
    private collectDescendantIds;
    /** Executes the move operation */
    ExecuteMove(): Promise<void>;
    OpenMergeIntoDialog(node: TaxTreeNode): void;
    OnMergeTargetSelected(value: unknown): void;
    CloseMergeIntoDialog(): void;
    /** Returns flat list of tags eligible as merge targets (excludes the source tag) */
    GetMergeTargetOptions(): {
        ID: string;
        Name: string;
        Depth: number;
        ItemCount: number;
    }[];
    ExecuteMergeInto(): Promise<void>;
    /** Opens treemap drill-in panel for the given cell */
    OpenTreemapDrillIn(cell: TaxTreemapCell): void;
    /** Closes treemap drill-in panel */
    CloseTreemapDrillIn(): void;
    /** Navigate from treemap drill-in to the tag in the tree view */
    DrillInToTreeView(node: TaxTreeNode): void;
    RefreshTaxonomyData(): Promise<void>;
    static ɵfac: i0.ɵɵFactoryDeclaration<ClassifyTaxonomyTabComponent, never>;
    static ɵcmp: i0.ɵɵComponentDeclaration<ClassifyTaxonomyTabComponent, "classify-taxonomy-tab", never, { "ContentTags": { "alias": "ContentTags"; "required": false; }; }, { "DataChanged": "DataChanged"; }, never, never, false, never>;
}
//# sourceMappingURL=taxonomy-tab.component.d.ts.map