import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core';
import * as d3 from 'd3';
import * as i0 from "@angular/core";
const _c0 = ["vennContainer"];
const _c1 = ["vennSvg"];
function VennDiagramComponent_Conditional_9_For_2_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "div", 9);
    i0.ɵɵelement(1, "div", 10);
    i0.ɵɵelementStart(2, "div", 11)(3, "span", 12);
    i0.ɵɵtext(4);
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(5, "span", 13);
    i0.ɵɵtext(6);
    i0.ɵɵelementEnd()()();
} if (rf & 2) {
    const set_r1 = ctx.$implicit;
    i0.ɵɵadvance();
    i0.ɵɵstyleProp("background-color", set_r1.color);
    i0.ɵɵadvance(3);
    i0.ɵɵtextInterpolate(set_r1.listName);
    i0.ɵɵadvance(2);
    i0.ɵɵtextInterpolate1("", set_r1.size, " items");
} }
function VennDiagramComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "div", 7);
    i0.ɵɵrepeaterCreate(1, VennDiagramComponent_Conditional_9_For_2_Template, 7, 4, "div", 9, i0.ɵɵrepeaterTrackByIdentity);
    i0.ɵɵelementEnd();
} if (rf & 2) {
    const ctx_r1 = i0.ɵɵnextContext();
    i0.ɵɵadvance();
    i0.ɵɵrepeater(ctx_r1.data.sets);
} }
function VennDiagramComponent_Conditional_10_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "div", 8);
    i0.ɵɵelement(1, "i", 14);
    i0.ɵɵelementStart(2, "p");
    i0.ɵɵtext(3, "Add lists to visualize their overlaps");
    i0.ɵɵelementEnd()();
} }
/**
 * Interactive D3-based Venn diagram component for visualizing list overlaps.
 *
 * Features:
 * - Proportional circle sizing based on list size
 * - Animated transitions
 * - Hover highlighting
 * - Click to select regions
 * - Responsive sizing
 */
export class VennDiagramComponent {
    cdr;
    containerRef;
    svgRef;
    data = null;
    selectedRegion = null;
    regionClick = new EventEmitter();
    regionHover = new EventEmitter();
    // Tooltip state
    tooltipVisible = false;
    tooltipX = 0;
    tooltipY = 0;
    tooltipTitle = '';
    tooltipCount = 0;
    // Track if hovering an intersection label (to suppress circle tooltips)
    isHoveringIntersectionLabel = false;
    svg = null;
    resizeObserver = null;
    width = 0;
    height = 0;
    constructor(cdr) {
        this.cdr = cdr;
    }
    /**
     * Apply the view-vs-list visual distinction to a circle selection: views
     * get a dashed colored stroke; lists get nothing extra (fill-only).
     * Centralized here so all 5 circle-drawing sites stay consistent.
     */
    applyOperandStyle(selection, set) {
        if (set.kind === 'view') {
            selection
                .attr('stroke', set.color)
                .attr('stroke-width', 3)
                .attr('stroke-dasharray', '6 4');
        }
    }
    ngAfterViewInit() {
        this.initializeSvg();
        this.setupResizeObserver();
        this.render();
    }
    ngOnChanges(changes) {
        if ((changes['data'] || changes['selectedRegion']) && this.svg) {
            this.render();
        }
    }
    ngOnDestroy() {
        if (this.resizeObserver) {
            this.resizeObserver.disconnect();
        }
    }
    initializeSvg() {
        if (!this.svgRef)
            return;
        this.svg = d3.select(this.svgRef.nativeElement);
        this.updateDimensions();
    }
    setupResizeObserver() {
        if (!this.containerRef)
            return;
        this.resizeObserver = new ResizeObserver(() => {
            this.updateDimensions();
            this.render();
        });
        this.resizeObserver.observe(this.containerRef.nativeElement);
    }
    updateDimensions() {
        if (!this.containerRef)
            return;
        const rect = this.containerRef.nativeElement.getBoundingClientRect();
        this.width = rect.width;
        this.height = rect.height;
    }
    render() {
        if (!this.svg || !this.data || this.data.sets.length === 0) {
            if (this.svg) {
                this.svg.selectAll('*').remove();
            }
            return;
        }
        // Clear previous content
        this.svg.selectAll('*').remove();
        const margin = { top: 40, right: 40, bottom: 80, left: 40 };
        const drawWidth = this.width - margin.left - margin.right;
        const drawHeight = this.height - margin.top - margin.bottom;
        if (drawWidth <= 0 || drawHeight <= 0)
            return;
        const g = this.svg
            .append('g')
            .attr('transform', `translate(${margin.left}, ${margin.top})`);
        // Render based on number of sets
        const sets = this.data.sets;
        if (sets.length === 1) {
            this.renderSingleSet(g, sets[0], drawWidth, drawHeight);
        }
        else if (sets.length === 2) {
            this.renderTwoSets(g, sets, drawWidth, drawHeight);
        }
        else if (sets.length === 3) {
            this.renderThreeSets(g, sets, drawWidth, drawHeight);
        }
        else if (sets.length === 4) {
            this.renderFourSets(g, sets, drawWidth, drawHeight);
        }
        else {
            this.renderMultipleSets(g, sets, drawWidth, drawHeight);
        }
    }
    renderSingleSet(g, set, width, height) {
        const cx = width / 2;
        const cy = height / 2;
        const radius = Math.min(width, height) * 0.35;
        // Draw circle
        const circle = g.append('circle')
            .attr('class', 'venn-circle')
            .attr('cx', cx)
            .attr('cy', cy)
            .attr('r', radius)
            .attr('fill', set.color)
            .attr('opacity', 0.6)
            .on('mouseenter', (event) => this.showCircleTooltip(event, set.listName, set.size))
            .on('mousemove', (event) => this.moveTooltip(event))
            .on('mouseleave', () => this.hideTooltip())
            .on('click', () => this.onCircleClick(set));
        this.applyOperandStyle(circle, set);
        // Draw label
        g.append('text')
            .attr('class', 'venn-label')
            .attr('x', cx)
            .attr('y', cy)
            .text(set.size.toString());
    }
    renderTwoSets(g, sets, width, height) {
        const cy = height / 2;
        // Calculate proportional radii based on list sizes
        const { radii, baseRadius } = this.calculateProportionalRadii(sets, width, height, 2);
        const r1 = radii[0];
        const r2 = radii[1];
        // Size the overlap by the **actual** intersection count, not a fixed
        // fraction. Otherwise the diagram lies: it always draws the circles
        // overlapping even when the lists share zero records, leading users
        // to expect a non-zero intersection that the math correctly returns
        // as 0. Math: as fraction of (r1+r2)/2, scale by share of records
        // common to both sets vs. the smaller set's size. Clamped so even
        // big intersections don't make one circle swallow the other.
        const intersectionSize = this.data?.intersections.find(i => i.setIds.length === 2 && i.setIds.includes(sets[0].listId) && i.setIds.includes(sets[1].listId))?.size ?? 0;
        const smallerSize = Math.min(sets[0].size, sets[1].size);
        const overlapFraction = smallerSize > 0 ? Math.min(0.85, intersectionSize / smallerSize) : 0;
        const avgRadius = (r1 + r2) / 2;
        // Visual gap when truly disjoint, so users can see "no overlap = no shared records".
        const overlap = intersectionSize > 0 ? avgRadius * Math.max(0.1, overlapFraction * 0.7) : -avgRadius * 0.15;
        const positions = [
            { cx: width / 2 - r1 + overlap / 2, r: r1, set: sets[0] },
            { cx: width / 2 + r2 - overlap / 2, r: r2, set: sets[1] }
        ];
        // Draw circles
        for (const pos of positions) {
            const circle = g.append('circle')
                .attr('class', 'venn-circle')
                .attr('cx', pos.cx)
                .attr('cy', cy)
                .attr('r', pos.r)
                .attr('fill', pos.set.color)
                .attr('opacity', 0.5)
                .on('mouseenter', (event) => this.showCircleTooltip(event, pos.set.listName, pos.set.size))
                .on('mousemove', (event) => this.moveTooltip(event))
                .on('mouseleave', () => this.hideTooltip())
                .on('click', () => this.onCircleClick(pos.set));
            this.applyOperandStyle(circle, pos.set);
        }
        // Find intersection data
        const intersection = this.data?.intersections.find(i => i.setIds.length === 2 && i.setIds.includes(sets[0].listId) && i.setIds.includes(sets[1].listId));
        // Draw intersection labels
        const leftOnlyIntersection = this.data?.intersections.find(i => i.setIds.length === 1 && i.setIds[0] === sets[0].listId);
        const rightOnlyIntersection = this.data?.intersections.find(i => i.setIds.length === 1 && i.setIds[0] === sets[1].listId);
        // Left only - clickable region
        if (leftOnlyIntersection) {
            this.addClickableLabel(g, positions[0].cx - positions[0].r * 0.3, cy, leftOnlyIntersection);
        }
        // Right only - clickable region
        if (rightOnlyIntersection) {
            this.addClickableLabel(g, positions[1].cx + positions[1].r * 0.3, cy, rightOnlyIntersection);
        }
        // Intersection - clickable region (center between the two circles)
        if (intersection && intersection.size > 0) {
            this.addClickableLabel(g, width / 2, cy, intersection);
        }
    }
    /**
     * Add a clickable label with background for intersection regions
     */
    addClickableLabel(g, x, y, intersection) {
        const labelGroup = g.append('g')
            .attr('class', 'intersection-label-group')
            .style('cursor', 'pointer');
        // Add background circle/pill for better click target
        const text = intersection.size.toString();
        const padding = 8;
        const fontSize = intersection.setIds.length >= 3 ? 14 : 12;
        const rectWidth = Math.max(text.length * fontSize * 0.7 + padding * 2, 32);
        // The rect is the main hover/click target
        const rect = labelGroup.append('rect')
            .attr('x', x - rectWidth / 2)
            .attr('y', y - fontSize / 2 - padding / 2)
            .attr('width', rectWidth)
            .attr('height', fontSize + padding)
            .attr('rx', (fontSize + padding) / 2)
            .attr('ry', (fontSize + padding) / 2)
            .attr('fill', 'rgba(0,0,0,0.6)')
            .attr('class', this.isRegionSelected(intersection) ? 'intersection-region selected' : 'intersection-region');
        // Text has pointer-events: none to prevent hover flickering
        labelGroup.append('text')
            .attr('class', 'venn-label')
            .attr('x', x)
            .attr('y', y + fontSize * 0.35)
            .style('font-size', `${fontSize}px`)
            .style('pointer-events', 'none')
            .text(text);
        // Attach events to the rect (the main clickable area)
        // Show tooltip for intersection labels with proper event handling to prevent flickering
        rect
            .on('mouseenter', (event) => {
            event.stopPropagation();
            // Set flag to suppress circle tooltips and prevent their mousemove from calling detectChanges
            this.isHoveringIntersectionLabel = true;
            // Hide any existing tooltip immediately without triggering detectChanges
            this.tooltipVisible = false;
            // Show the label's tooltip
            this.showLabelTooltip(event, intersection);
        })
            .on('mousemove', (event) => {
            event.stopPropagation();
            // Update tooltip position without calling detectChanges (avoid flicker)
            this.moveLabelTooltipPosition(event);
        })
            .on('mouseleave', (event) => {
            event.stopPropagation();
            this.isHoveringIntersectionLabel = false;
            this.tooltipVisible = false;
            this.cdr.detectChanges();
        })
            .on('click', (event) => {
            event.stopPropagation();
            this.onIntersectionClick(intersection);
        });
    }
    /**
     * Check if a region is currently selected
     */
    isRegionSelected(intersection) {
        if (!this.selectedRegion)
            return false;
        return this.selectedRegion.setIds.length === intersection.setIds.length &&
            this.selectedRegion.setIds.every(id => intersection.setIds.includes(id));
    }
    /**
     * Calculate proportional radii using a small/medium/large approach
     * This avoids extreme size differences (e.g., 1000 vs 10 items)
     */
    calculateProportionalRadii(sets, width, height, numSets) {
        // Determine base radius based on number of sets
        let baseRadius;
        if (numSets === 1) {
            baseRadius = Math.min(width, height) * 0.35;
        }
        else if (numSets === 2) {
            baseRadius = Math.min(width / 2.5, height / 2) * 0.8;
        }
        else if (numSets === 3) {
            baseRadius = Math.min(width, height) * 0.28;
        }
        else {
            const cols = Math.ceil(Math.sqrt(numSets));
            const cellSize = Math.min(width / cols, height / cols);
            baseRadius = cellSize * 0.35;
        }
        // Find the size range
        const sizes = sets.map(s => s.size);
        const maxSize = Math.max(...sizes, 1);
        const minSize = Math.min(...sizes, 1);
        // If all same size or very close, use same radius
        if (maxSize === minSize || maxSize / minSize < 1.5) {
            return {
                radii: sets.map(() => baseRadius),
                baseRadius
            };
        }
        // Use logarithmic scaling with bounds for visual balance
        // Scale factor ranges from 0.7 to 1.0 based on relative size
        const minScale = 0.7;
        const maxScale = 1.0;
        const radii = sets.map(set => {
            // Use log scale for smoother visual representation
            const logMin = Math.log(minSize + 1);
            const logMax = Math.log(maxSize + 1);
            const logSize = Math.log(set.size + 1);
            // Normalize to 0-1 range
            const normalized = (logSize - logMin) / (logMax - logMin);
            // Scale to minScale-maxScale range
            const scale = minScale + normalized * (maxScale - minScale);
            return baseRadius * scale;
        });
        return { radii, baseRadius };
    }
    renderThreeSets(g, sets, width, height) {
        const cx = width / 2;
        const cy = height / 2;
        // Calculate proportional radii based on list sizes
        const { radii, baseRadius } = this.calculateProportionalRadii(sets, width, height, 3);
        const avgRadius = radii.reduce((a, b) => a + b, 0) / radii.length;
        const offset = avgRadius * 0.65; // Distance from center
        // Position circles in a triangle with individual radii
        const positions = [
            { cx: cx, cy: cy - offset * 0.8, r: radii[0], set: sets[0] }, // Top
            { cx: cx - offset * 0.9, cy: cy + offset * 0.5, r: radii[1], set: sets[1] }, // Bottom left
            { cx: cx + offset * 0.9, cy: cy + offset * 0.5, r: radii[2], set: sets[2] } // Bottom right
        ];
        // Draw circles
        for (const pos of positions) {
            const circle = g.append('circle')
                .attr('class', 'venn-circle')
                .attr('cx', pos.cx)
                .attr('cy', pos.cy)
                .attr('r', pos.r)
                .attr('fill', pos.set.color)
                .attr('opacity', 0.5)
                .on('mouseenter', (event) => this.showCircleTooltip(event, pos.set.listName, pos.set.size))
                .on('mousemove', (event) => this.moveTooltip(event))
                .on('mouseleave', () => this.hideTooltip())
                .on('click', () => this.onCircleClick(pos.set));
            this.applyOperandStyle(circle, pos.set);
        }
        // Draw clickable intersection labels
        for (const intersection of this.data?.intersections || []) {
            const labelPos = this.getIntersectionLabelPosition(intersection, positions, cx, cy, avgRadius);
            if (labelPos && intersection.size > 0) {
                this.addClickableLabel(g, labelPos.x, labelPos.y, intersection);
            }
        }
    }
    getIntersectionLabelPosition(intersection, positions, cx, cy, radius) {
        const n = intersection.setIds.length;
        if (n === 1) {
            // Find the single set position
            const pos = positions.find(p => p.set.listId === intersection.setIds[0]);
            if (!pos)
                return null;
            // Use individual radius if available, otherwise use provided radius
            const r = pos.r || radius;
            // Move label towards the outer edge, away from center
            const dx = pos.cx - cx;
            const dy = pos.cy - cy;
            const dist = Math.sqrt(dx * dx + dy * dy);
            const offsetFactor = 0.6;
            return {
                x: pos.cx + (dx / dist) * r * offsetFactor,
                y: pos.cy + (dy / dist) * r * offsetFactor
            };
        }
        else if (n === 2) {
            // Average of two positions
            const pos1 = positions.find(p => p.set.listId === intersection.setIds[0]);
            const pos2 = positions.find(p => p.set.listId === intersection.setIds[1]);
            if (!pos1 || !pos2)
                return null;
            return {
                x: (pos1.cx + pos2.cx) / 2,
                y: (pos1.cy + pos2.cy) / 2
            };
        }
        else if (n === 3) {
            // Center of all three
            return { x: cx, y: cy };
        }
        return null;
    }
    /**
     * Render a 4-set Venn diagram using overlapping ellipses.
     * This is a simplified approach - true 4-set Venn diagrams use complex curves.
     * We use two pairs of rotated ellipses to create all 15 possible regions.
     */
    renderFourSets(g, sets, width, height) {
        const cx = width / 2;
        const cy = height / 2;
        // Use ellipses for 4-set Venn
        const baseSize = Math.min(width, height) * 0.35;
        const rx = baseSize * 1.2; // Ellipse horizontal radius
        const ry = baseSize * 0.7; // Ellipse vertical radius
        // Position ellipses with rotations to create overlapping regions
        // Two ellipses rotated ~45 degrees and two rotated ~-45 degrees
        const positions = [
            { cx: cx - baseSize * 0.3, cy: cy - baseSize * 0.15, rx, ry, rotation: 45, set: sets[0] },
            { cx: cx + baseSize * 0.3, cy: cy - baseSize * 0.15, rx, ry, rotation: -45, set: sets[1] },
            { cx: cx - baseSize * 0.3, cy: cy + baseSize * 0.15, rx, ry, rotation: -45, set: sets[2] },
            { cx: cx + baseSize * 0.3, cy: cy + baseSize * 0.15, rx, ry, rotation: 45, set: sets[3] }
        ];
        // Draw ellipses
        for (const pos of positions) {
            const ellipse = g.append('ellipse')
                .attr('class', 'venn-circle')
                .attr('cx', pos.cx)
                .attr('cy', pos.cy)
                .attr('rx', pos.rx)
                .attr('ry', pos.ry)
                .attr('transform', `rotate(${pos.rotation}, ${pos.cx}, ${pos.cy})`)
                .attr('fill', pos.set.color)
                .attr('opacity', 0.4)
                .on('mouseenter', (event) => this.showCircleTooltip(event, pos.set.listName, pos.set.size))
                .on('mousemove', (event) => this.moveTooltip(event))
                .on('mouseleave', () => this.hideTooltip())
                .on('click', () => this.onCircleClick(pos.set));
            this.applyOperandStyle(ellipse, pos.set);
        }
        // Draw clickable intersection labels
        // For 4 sets, we need to calculate positions for all 15 regions
        for (const intersection of this.data?.intersections || []) {
            const labelPos = this.getFourSetIntersectionPosition(intersection, positions, cx, cy, baseSize);
            if (labelPos && intersection.size > 0) {
                this.addClickableLabel(g, labelPos.x, labelPos.y, intersection);
            }
        }
    }
    /**
     * Calculate label position for 4-set Venn intersections
     */
    getFourSetIntersectionPosition(intersection, positions, cx, cy, baseSize) {
        const n = intersection.setIds.length;
        const setIndices = intersection.setIds.map(id => positions.findIndex(p => p.set.listId === id)).filter(i => i >= 0);
        if (setIndices.length !== n)
            return null;
        if (n === 1) {
            // Single set - position at outer edge
            const pos = positions[setIndices[0]];
            const dx = pos.cx - cx;
            const dy = pos.cy - cy;
            const dist = Math.sqrt(dx * dx + dy * dy) || 1;
            return {
                x: pos.cx + (dx / dist) * baseSize * 0.6,
                y: pos.cy + (dy / dist) * baseSize * 0.6
            };
        }
        else if (n === 2) {
            // Two sets - average position, offset from center
            const pos1 = positions[setIndices[0]];
            const pos2 = positions[setIndices[1]];
            const avgX = (pos1.cx + pos2.cx) / 2;
            const avgY = (pos1.cy + pos2.cy) / 2;
            // Offset slightly from the center
            const dx = avgX - cx;
            const dy = avgY - cy;
            const dist = Math.sqrt(dx * dx + dy * dy) || 1;
            return {
                x: avgX + (dx / dist) * baseSize * 0.2,
                y: avgY + (dy / dist) * baseSize * 0.2
            };
        }
        else if (n === 3) {
            // Three sets - find the set NOT in the intersection
            const missingIndex = [0, 1, 2, 3].find(i => !setIndices.includes(i));
            if (missingIndex === undefined)
                return { x: cx, y: cy };
            // Position opposite to the missing set
            const missingPos = positions[missingIndex];
            const dx = cx - missingPos.cx;
            const dy = cy - missingPos.cy;
            const dist = Math.sqrt(dx * dx + dy * dy) || 1;
            return {
                x: cx + (dx / dist) * baseSize * 0.25,
                y: cy + (dy / dist) * baseSize * 0.25
            };
        }
        else if (n === 4) {
            // All four sets - center
            return { x: cx, y: cy };
        }
        return null;
    }
    renderMultipleSets(g, sets, width, height) {
        // For more than 3 sets, use a grid layout
        const cols = Math.ceil(Math.sqrt(sets.length));
        const rows = Math.ceil(sets.length / cols);
        const cellWidth = width / cols;
        const cellHeight = height / rows;
        const radius = Math.min(cellWidth, cellHeight) * 0.35;
        sets.forEach((set, i) => {
            const col = i % cols;
            const row = Math.floor(i / cols);
            const cx = cellWidth * col + cellWidth / 2;
            const cy = cellHeight * row + cellHeight / 2;
            const circle = g.append('circle')
                .attr('class', 'venn-circle')
                .attr('cx', cx)
                .attr('cy', cy)
                .attr('r', radius)
                .attr('fill', set.color)
                .attr('opacity', 0.6)
                .on('mouseenter', (event) => this.showCircleTooltip(event, set.listName, set.size))
                .on('mousemove', (event) => this.moveTooltip(event))
                .on('mouseleave', () => this.hideTooltip())
                .on('click', () => this.onCircleClick(set));
            this.applyOperandStyle(circle, set);
            g.append('text')
                .attr('class', 'venn-label')
                .attr('x', cx)
                .attr('y', cy)
                .text(set.size.toString());
            // Add list name below
            g.append('text')
                .attr('x', cx)
                .attr('y', cy + radius + 16)
                .attr('text-anchor', 'middle')
                .attr('fill', 'var(--mj-text-secondary)')
                .attr('font-size', '11px')
                .text(set.listName.length > 15 ? set.listName.substring(0, 15) + '...' : set.listName);
        });
    }
    /**
     * Show tooltip for circle/ellipse elements.
     * This is suppressed when hovering an intersection label.
     */
    showCircleTooltip(event, title, count) {
        // Don't show circle tooltip if hovering an intersection label
        if (this.isHoveringIntersectionLabel) {
            return;
        }
        this.showTooltip(event, title, count);
    }
    showTooltip(event, title, count) {
        this.tooltipTitle = title;
        this.tooltipCount = count;
        this.tooltipVisible = true;
        this.moveTooltip(event);
        this.cdr.detectChanges();
    }
    moveTooltip(event) {
        // Skip updating if hovering an intersection label (prevents flicker from circle mousemove events)
        if (this.isHoveringIntersectionLabel) {
            return;
        }
        const container = this.containerRef?.nativeElement;
        if (!container)
            return;
        const rect = container.getBoundingClientRect();
        this.tooltipX = event.clientX - rect.left + 10;
        this.tooltipY = event.clientY - rect.top - 30;
        this.cdr.detectChanges();
    }
    /**
     * Show tooltip for intersection label with proper intersection name
     */
    showLabelTooltip(event, intersection) {
        // Build the tooltip title from the intersection
        const setNames = intersection.setIds.map(id => {
            const set = this.data?.sets.find(s => s.listId === id);
            return set?.listName || 'Unknown';
        });
        if (intersection.setIds.length === 1) {
            this.tooltipTitle = `Only in ${setNames[0]}`;
        }
        else {
            this.tooltipTitle = setNames.join(' ∩ ');
        }
        this.tooltipCount = intersection.size;
        this.tooltipVisible = true;
        this.moveLabelTooltipPosition(event);
        this.cdr.detectChanges();
    }
    /**
     * Update tooltip position for label without triggering extra change detection
     */
    moveLabelTooltipPosition(event) {
        const container = this.containerRef?.nativeElement;
        if (!container)
            return;
        const rect = container.getBoundingClientRect();
        this.tooltipX = event.clientX - rect.left + 10;
        this.tooltipY = event.clientY - rect.top - 30;
        // Don't call detectChanges here - we call it once in showLabelTooltip
        // and the Angular zone will handle the position updates
    }
    hideTooltip() {
        // Don't hide tooltip if we're hovering an intersection label
        if (this.isHoveringIntersectionLabel) {
            return;
        }
        this.tooltipVisible = false;
        this.cdr.detectChanges();
    }
    onCircleClick(set) {
        // Find the "only in this set" intersection
        const intersection = this.data?.intersections.find(i => i.setIds.length === 1 && i.setIds[0] === set.listId);
        if (intersection) {
            this.regionClick.emit({
                intersection,
                recordIds: intersection.recordIds
            });
        }
    }
    onIntersectionClick(intersection) {
        this.regionClick.emit({
            intersection,
            recordIds: intersection.recordIds
        });
    }
    static ɵfac = function VennDiagramComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || VennDiagramComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
    static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: VennDiagramComponent, selectors: [["mj-venn-diagram"]], viewQuery: function VennDiagramComponent_Query(rf, ctx) { if (rf & 1) {
            i0.ɵɵviewQuery(_c0, 5)(_c1, 5);
        } if (rf & 2) {
            let _t;
            i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.containerRef = _t.first);
            i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.svgRef = _t.first);
        } }, inputs: { data: "data", selectedRegion: "selectedRegion" }, outputs: { regionClick: "regionClick", regionHover: "regionHover" }, standalone: false, features: [i0.ɵɵNgOnChangesFeature], decls: 11, vars: 10, consts: [["vennContainer", ""], ["vennSvg", ""], [1, "venn-container"], [1, "venn-svg"], [1, "venn-tooltip"], [1, "tooltip-title"], [1, "tooltip-count"], [1, "venn-legend"], [1, "empty-state"], [1, "legend-item"], [1, "legend-color"], [1, "legend-info"], [1, "legend-name"], [1, "legend-count"], [1, "fa-solid", "fa-diagram-project"]], template: function VennDiagramComponent_Template(rf, ctx) { if (rf & 1) {
            i0.ɵɵelementStart(0, "div", 2, 0);
            i0.ɵɵnamespaceSVG();
            i0.ɵɵelement(2, "svg", 3, 1);
            i0.ɵɵnamespaceHTML();
            i0.ɵɵelementStart(4, "div", 4)(5, "div", 5);
            i0.ɵɵtext(6);
            i0.ɵɵelementEnd();
            i0.ɵɵelementStart(7, "div", 6);
            i0.ɵɵtext(8);
            i0.ɵɵelementEnd()();
            i0.ɵɵconditionalCreate(9, VennDiagramComponent_Conditional_9_Template, 3, 0, "div", 7);
            i0.ɵɵconditionalCreate(10, VennDiagramComponent_Conditional_10_Template, 4, 0, "div", 8);
            i0.ɵɵelementEnd();
        } if (rf & 2) {
            i0.ɵɵadvance(4);
            i0.ɵɵstyleProp("left", ctx.tooltipX, "px")("top", ctx.tooltipY, "px");
            i0.ɵɵclassProp("visible", ctx.tooltipVisible);
            i0.ɵɵadvance(2);
            i0.ɵɵtextInterpolate(ctx.tooltipTitle);
            i0.ɵɵadvance(2);
            i0.ɵɵtextInterpolate1("", ctx.tooltipCount, " records");
            i0.ɵɵadvance();
            i0.ɵɵconditional(ctx.data && ctx.data.sets.length > 0 ? 9 : -1);
            i0.ɵɵadvance();
            i0.ɵɵconditional(!ctx.data || ctx.data.sets.length === 0 ? 10 : -1);
        } }, styles: ["[_nghost-%COMP%] {\n      display: block;\n      width: 100%;\n      height: 100%;\n    }\n\n    .venn-container[_ngcontent-%COMP%] {\n      position: relative;\n      width: 100%;\n      height: 100%;\n      min-height: 300px;\n      background: linear-gradient(135deg, var(--mj-bg-surface-sunken) 0%, var(--mj-bg-surface-card) 100%);\n      border-radius: 8px;\n      overflow: hidden;\n    }\n\n    .venn-svg[_ngcontent-%COMP%] {\n      width: 100%;\n      height: 100%;\n    }\n\n    .venn-tooltip[_ngcontent-%COMP%] {\n      position: absolute;\n      background: rgba(0, 0, 0, 0.85);\n      color: white;\n      padding: 8px 12px;\n      border-radius: 6px;\n      font-size: 13px;\n      pointer-events: none;\n      opacity: 0;\n      transform: translateY(8px);\n      transition: opacity 0.15s, transform 0.15s;\n      z-index: 100;\n      white-space: nowrap;\n    }\n\n    .venn-tooltip.visible[_ngcontent-%COMP%] {\n      opacity: 1;\n      transform: translateY(0);\n    }\n\n    .tooltip-title[_ngcontent-%COMP%] {\n      font-weight: 600;\n      margin-bottom: 2px;\n    }\n\n    .tooltip-count[_ngcontent-%COMP%] {\n      color: rgba(255, 255, 255, 0.8);\n      font-size: 12px;\n    }\n\n    .venn-legend[_ngcontent-%COMP%] {\n      position: absolute;\n      bottom: 16px;\n      left: 16px;\n      display: flex;\n      flex-direction: column;\n      gap: 8px;\n      background: var(--mj-bg-surface-card);\n      padding: 12px;\n      border-radius: 8px;\n      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n    }\n\n    .legend-item[_ngcontent-%COMP%] {\n      display: flex;\n      align-items: center;\n      gap: 10px;\n    }\n\n    .legend-color[_ngcontent-%COMP%] {\n      width: 16px;\n      height: 16px;\n      border-radius: 4px;\n      flex-shrink: 0;\n    }\n\n    .legend-info[_ngcontent-%COMP%] {\n      display: flex;\n      flex-direction: column;\n    }\n\n    .legend-name[_ngcontent-%COMP%] {\n      font-size: 13px;\n      font-weight: 500;\n      color: var(--mj-text-primary);\n    }\n\n    .legend-count[_ngcontent-%COMP%] {\n      font-size: 11px;\n      color: var(--mj-text-muted);\n    }\n\n    .empty-state[_ngcontent-%COMP%] {\n      position: absolute;\n      top: 50%;\n      left: 50%;\n      transform: translate(-50%, -50%);\n      text-align: center;\n      color: var(--mj-text-muted);\n    }\n\n    .empty-state[_ngcontent-%COMP%]   i[_ngcontent-%COMP%] {\n      font-size: 48px;\n      margin-bottom: 16px;\n      opacity: 0.5;\n    }\n\n    .empty-state[_ngcontent-%COMP%]   p[_ngcontent-%COMP%] {\n      font-size: 14px;\n      margin: 0;\n    }\n\n    \n\n    [_nghost-%COMP%]     .venn-circle {\n      cursor: pointer;\n      transition: opacity 0.2s;\n    }\n\n    [_nghost-%COMP%]     .venn-circle:hover {\n      opacity: 0.9;\n    }\n\n    [_nghost-%COMP%]     .venn-label {\n      font-size: 12px;\n      font-weight: 600;\n      fill: white;\n      text-anchor: middle;\n      pointer-events: none;\n    }\n\n    [_nghost-%COMP%]     .intersection-region {\n      cursor: pointer;\n      transition: all 0.2s;\n    }\n\n    [_nghost-%COMP%]     .intersection-region:hover {\n      fill: rgba(0,0,0,0.75);\n    }\n\n    [_nghost-%COMP%]     .intersection-region.selected {\n      fill: rgba(156, 39, 176, 0.9);\n      stroke: #7B1FA2;\n      stroke-width: 2;\n    }\n\n    [_nghost-%COMP%]     .intersection-label-group {\n      transition: transform 0.15s ease;\n    }\n\n    [_nghost-%COMP%]     .intersection-label-group:hover {\n      transform: scale(1.05);\n    }"] });
}
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(VennDiagramComponent, [{
        type: Component,
        args: [{ standalone: false, selector: 'mj-venn-diagram', template: `
    <div class="venn-container" #vennContainer>
      <svg #vennSvg class="venn-svg"></svg>
    
      <!-- Tooltip -->
      <div class="venn-tooltip" [class.visible]="tooltipVisible"
        [style.left.px]="tooltipX" [style.top.px]="tooltipY">
        <div class="tooltip-title">{{ tooltipTitle }}</div>
        <div class="tooltip-count">{{ tooltipCount }} records</div>
      </div>
    
      <!-- Legend -->
      @if (data && data.sets.length > 0) {
        <div class="venn-legend">
          @for (set of data.sets; track set) {
            <div class="legend-item">
              <div class="legend-color" [style.background-color]="set.color"></div>
              <div class="legend-info">
                <span class="legend-name">{{ set.listName }}</span>
                <span class="legend-count">{{ set.size }} items</span>
              </div>
            </div>
          }
        </div>
      }
    
      <!-- Empty state -->
      @if (!data || data.sets.length === 0) {
        <div class="empty-state">
          <i class="fa-solid fa-diagram-project"></i>
          <p>Add lists to visualize their overlaps</p>
        </div>
      }
    </div>
    `, styles: ["\n    :host {\n      display: block;\n      width: 100%;\n      height: 100%;\n    }\n\n    .venn-container {\n      position: relative;\n      width: 100%;\n      height: 100%;\n      min-height: 300px;\n      background: linear-gradient(135deg, var(--mj-bg-surface-sunken) 0%, var(--mj-bg-surface-card) 100%);\n      border-radius: 8px;\n      overflow: hidden;\n    }\n\n    .venn-svg {\n      width: 100%;\n      height: 100%;\n    }\n\n    .venn-tooltip {\n      position: absolute;\n      background: rgba(0, 0, 0, 0.85);\n      color: white;\n      padding: 8px 12px;\n      border-radius: 6px;\n      font-size: 13px;\n      pointer-events: none;\n      opacity: 0;\n      transform: translateY(8px);\n      transition: opacity 0.15s, transform 0.15s;\n      z-index: 100;\n      white-space: nowrap;\n    }\n\n    .venn-tooltip.visible {\n      opacity: 1;\n      transform: translateY(0);\n    }\n\n    .tooltip-title {\n      font-weight: 600;\n      margin-bottom: 2px;\n    }\n\n    .tooltip-count {\n      color: rgba(255, 255, 255, 0.8);\n      font-size: 12px;\n    }\n\n    .venn-legend {\n      position: absolute;\n      bottom: 16px;\n      left: 16px;\n      display: flex;\n      flex-direction: column;\n      gap: 8px;\n      background: var(--mj-bg-surface-card);\n      padding: 12px;\n      border-radius: 8px;\n      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n    }\n\n    .legend-item {\n      display: flex;\n      align-items: center;\n      gap: 10px;\n    }\n\n    .legend-color {\n      width: 16px;\n      height: 16px;\n      border-radius: 4px;\n      flex-shrink: 0;\n    }\n\n    .legend-info {\n      display: flex;\n      flex-direction: column;\n    }\n\n    .legend-name {\n      font-size: 13px;\n      font-weight: 500;\n      color: var(--mj-text-primary);\n    }\n\n    .legend-count {\n      font-size: 11px;\n      color: var(--mj-text-muted);\n    }\n\n    .empty-state {\n      position: absolute;\n      top: 50%;\n      left: 50%;\n      transform: translate(-50%, -50%);\n      text-align: center;\n      color: var(--mj-text-muted);\n    }\n\n    .empty-state i {\n      font-size: 48px;\n      margin-bottom: 16px;\n      opacity: 0.5;\n    }\n\n    .empty-state p {\n      font-size: 14px;\n      margin: 0;\n    }\n\n    /* SVG styles */\n    :host ::ng-deep .venn-circle {\n      cursor: pointer;\n      transition: opacity 0.2s;\n    }\n\n    :host ::ng-deep .venn-circle:hover {\n      opacity: 0.9;\n    }\n\n    :host ::ng-deep .venn-label {\n      font-size: 12px;\n      font-weight: 600;\n      fill: white;\n      text-anchor: middle;\n      pointer-events: none;\n    }\n\n    :host ::ng-deep .intersection-region {\n      cursor: pointer;\n      transition: all 0.2s;\n    }\n\n    :host ::ng-deep .intersection-region:hover {\n      fill: rgba(0,0,0,0.75);\n    }\n\n    :host ::ng-deep .intersection-region.selected {\n      fill: rgba(156, 39, 176, 0.9);\n      stroke: #7B1FA2;\n      stroke-width: 2;\n    }\n\n    :host ::ng-deep .intersection-label-group {\n      transition: transform 0.15s ease;\n    }\n\n    :host ::ng-deep .intersection-label-group:hover {\n      transform: scale(1.05);\n    }\n  "] }]
    }], () => [{ type: i0.ChangeDetectorRef }], { containerRef: [{
            type: ViewChild,
            args: ['vennContainer']
        }], svgRef: [{
            type: ViewChild,
            args: ['vennSvg']
        }], data: [{
            type: Input
        }], selectedRegion: [{
            type: Input
        }], regionClick: [{
            type: Output
        }], regionHover: [{
            type: Output
        }] }); })();
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(VennDiagramComponent, { className: "VennDiagramComponent", filePath: "src/Lists/components/venn-diagram/venn-diagram.component.ts", lineNumber: 229 }); })();
//# sourceMappingURL=venn-diagram.component.js.map