/**
 * Tutorial system — generic engine, steps, tooltip positioning.
 */

import { activeTutorial, setActiveTutorial } from '../core/state.ts';
import { t } from '../core/i18n.ts';

interface TutorialStep {
    selector: string;
    textKey: string;
    position: string;
    global?: boolean;
}

interface TutorialConfig {
    steps: TutorialStep[];
    overlayId: string;
    mode: string;
    container: Element | null;
    resolveTarget: (step: TutorialStep) => Element | null;
    onClose?: (() => void) | null;
}

const calibrationTutorialSteps: TutorialStep[] = [
    { selector: '#cal-top-leds', textKey: 'calibration.tip.led_count', position: 'bottom' },
    { selector: '.corner-bottom-left', textKey: 'calibration.tip.start_corner', position: 'right' },
    { selector: '.direction-toggle', textKey: 'calibration.tip.direction', position: 'bottom' },
    { selector: '.edge-span-bar[data-edge="top"]', textKey: 'calibration.tip.span', position: 'bottom' },
    { selector: '.toggle-top', textKey: 'calibration.tip.test', position: 'top' },
    { selector: '#calibration-overlay-btn', textKey: 'calibration.tip.overlay', position: 'bottom' },
    { selector: '.preview-screen-total', textKey: 'calibration.tip.toggle_inputs', position: 'top' },
    { selector: '.preview-screen-border-width', textKey: 'calibration.tip.border_width', position: 'bottom' },
    { selector: '#cal-offset', textKey: 'calibration.tip.offset', position: 'top' },
    { selector: '#cal-skip-start', textKey: 'calibration.tip.skip_leds_start', position: 'top' },
    { selector: '#cal-skip-end', textKey: 'calibration.tip.skip_leds_end', position: 'top' }
];

const TOUR_KEY = 'tour_completed';

const gettingStartedSteps: TutorialStep[] = [
    { selector: 'header .header-title', textKey: 'tour.welcome', position: 'bottom' },
    { selector: '#tab-btn-dashboard', textKey: 'tour.dashboard', position: 'bottom' },
    { selector: '#tab-btn-automations', textKey: 'tour.automations', position: 'bottom' },
    { selector: '#tab-btn-targets', textKey: 'tour.targets', position: 'bottom' },
    { selector: '#tab-btn-streams', textKey: 'tour.sources', position: 'bottom' },
    { selector: '#tab-btn-graph', textKey: 'tour.graph', position: 'bottom' },
    { selector: 'a.header-link[href="/docs"]', textKey: 'tour.api', position: 'bottom' },
    { selector: '[onclick*="openCommandPalette"]', textKey: 'tour.search', position: 'bottom' },
    { selector: '[onclick*="toggleTheme"]', textKey: 'tour.theme', position: 'bottom' },
    { selector: '#cp-wrap-accent', textKey: 'tour.accent', position: 'bottom' },
    { selector: '[onclick*="openSettingsModal"]', textKey: 'tour.settings', position: 'bottom' },
    { selector: '#locale-select', textKey: 'tour.language', position: 'bottom' }
];

const dashboardTutorialSteps: TutorialStep[] = [
    { selector: '[data-dashboard-section="perf"]', textKey: 'tour.dash.perf', position: 'bottom' },
    { selector: '[data-dashboard-section="running"]', textKey: 'tour.dash.running', position: 'bottom' },
    { selector: '[data-dashboard-section="stopped"]', textKey: 'tour.dash.stopped', position: 'bottom' },
    { selector: '[data-dashboard-section="automations"]', textKey: 'tour.dash.automations', position: 'bottom' }
];

const targetsTutorialSteps: TutorialStep[] = [
    { selector: '[data-tree-group="led_group"]', textKey: 'tour.tgt.led_tab', position: 'right' },
    { selector: '[data-card-section="led-devices"]', textKey: 'tour.tgt.devices', position: 'bottom' },
    { selector: '[data-card-section="led-targets"]', textKey: 'tour.tgt.targets', position: 'bottom' },
    { selector: '[data-tree-group="kc_group"]', textKey: 'tour.tgt.kc_tab', position: 'right' }
];

const sourcesTourSteps: TutorialStep[] = [
    { selector: '#streams-tree-nav [data-tree-leaf="raw"]', textKey: 'tour.src.raw', position: 'right' },
    { selector: '[data-card-section="raw-templates"]', textKey: 'tour.src.templates', position: 'bottom' },
    { selector: '#streams-tree-nav [data-tree-leaf="static_image"]', textKey: 'tour.src.static', position: 'right' },
    { selector: '#streams-tree-nav [data-tree-leaf="processed"]', textKey: 'tour.src.processed', position: 'right' },
    { selector: '#streams-tree-nav [data-tree-leaf="color_strip"]', textKey: 'tour.src.color_strip', position: 'right' },
    { selector: '#streams-tree-nav [data-tree-leaf="audio"]', textKey: 'tour.src.audio', position: 'right' },
    { selector: '#streams-tree-nav [data-tree-leaf="value"]', textKey: 'tour.src.value', position: 'right' },
    { selector: '#streams-tree-nav [data-tree-leaf="sync"]', textKey: 'tour.src.sync', position: 'right' }
];

const automationsTutorialSteps: TutorialStep[] = [
    { selector: '[data-card-section="automations"]', textKey: 'tour.auto.list', position: 'bottom' },
    { selector: '[data-cs-add="automations"]', textKey: 'tour.auto.add', position: 'bottom' },
    { selector: '.card[data-automation-id]', textKey: 'tour.auto.card', position: 'bottom' },
    { selector: '[data-card-section="scenes"]', textKey: 'tour.auto.scenes_list', position: 'bottom' },
    { selector: '[data-cs-add="scenes"]', textKey: 'tour.auto.scenes_add', position: 'bottom' },
    { selector: '.card[data-scene-id]', textKey: 'tour.auto.scenes_card', position: 'bottom' },
];

const _fixedResolve = (step: TutorialStep): Element | null => {
    const el = document.querySelector(step.selector);
    if (!el) return null;
    // offsetParent is null when element or any ancestor has display:none
    if (!(el as HTMLElement).offsetParent) return null;
    return el;
};

const deviceTutorialSteps: TutorialStep[] = [
    { selector: '.card-subtitle', textKey: 'device.tip.metadata', position: 'bottom' },
    { selector: '.brightness-control', textKey: 'device.tip.brightness', position: 'bottom' },
    { selector: '.card-actions .btn:nth-child(1)', textKey: 'device.tip.start', position: 'top' },
    { selector: '.card-actions .btn:nth-child(2)', textKey: 'device.tip.settings', position: 'top' },
    { selector: '.card-actions .btn:nth-child(3)', textKey: 'device.tip.capture_settings', position: 'top' },
    { selector: '.card-actions .btn:nth-child(4)', textKey: 'device.tip.calibrate', position: 'top' },
    { selector: '.card-actions .btn:nth-child(5)', textKey: 'device.tip.webui', position: 'top' }
];

export function startTutorial(config: TutorialConfig): void {
    closeTutorial();
    // Remove focus from the trigger button so its outline doesn't persist
    if (document.activeElement) (document.activeElement as HTMLElement).blur();
    const overlay = document.getElementById(config.overlayId);
    if (!overlay) return;

    setActiveTutorial({
        steps: config.steps,
        overlay: overlay,
        mode: config.mode,
        step: 0,
        resolveTarget: config.resolveTarget,
        container: config.container,
        onClose: config.onClose || null
    });

    // Hide tooltip and ring until first step positions them (prevents flash at 0,0)
    const tooltip = overlay.querySelector('.tutorial-tooltip');
    const ring = overlay.querySelector('.tutorial-ring');
    const backdrop = overlay.querySelector('.tutorial-backdrop');
    if (tooltip) (tooltip as HTMLElement).style.visibility = 'hidden';
    if (ring) (ring as HTMLElement).style.visibility = 'hidden';
    if (backdrop) (backdrop as HTMLElement).style.clipPath = 'none';

    overlay.classList.add('active');
    document.addEventListener('keydown', handleTutorialKey);
    showTutorialStep(0);
}

export function startCalibrationTutorial(): void {
    const container = document.querySelector('#calibration-modal .modal-body');
    if (!container) return;
    startTutorial({
        steps: calibrationTutorialSteps,
        overlayId: 'calibration-tutorial-overlay',
        mode: 'absolute',
        container: container,
        resolveTarget: (step: TutorialStep): Element | null => {
            const el = document.querySelector(step.selector) as HTMLElement | null;
            if (!el) return null;
            // Skip elements hidden via display:none (e.g. overlay btn in device mode)
            if (el.style.display === 'none' || getComputedStyle(el).display === 'none') return null;
            return el;
        }
    });
}

export function startDeviceTutorial(deviceId?: string): void {
    const selector = deviceId
        ? `.card[data-device-id="${deviceId}"]`
        : '.card[data-device-id]';
    if (!document.querySelector(selector)) return;
    startTutorial({
        steps: deviceTutorialSteps,
        overlayId: 'device-tutorial-overlay',
        mode: 'fixed',
        container: null,
        resolveTarget: (step: TutorialStep): Element | null => {
            const card = document.querySelector(selector);
            if (!card) return null;
            return step.global
                ? document.querySelector(step.selector)
                : card.querySelector(step.selector);
        }
    });
}

export function startGettingStartedTutorial(): void {
    startTutorial({
        steps: gettingStartedSteps,
        overlayId: 'getting-started-overlay',
        mode: 'fixed',
        container: null,
        resolveTarget: (step: TutorialStep): Element | null => document.querySelector(step.selector) || null,
        onClose: () => localStorage.setItem(TOUR_KEY, '1')
    });
}

export function startDashboardTutorial(): void {
    startTutorial({
        steps: dashboardTutorialSteps,
        overlayId: 'getting-started-overlay',
        mode: 'fixed',
        container: null,
        resolveTarget: _fixedResolve
    });
}

export function startTargetsTutorial(): void {
    startTutorial({
        steps: targetsTutorialSteps,
        overlayId: 'getting-started-overlay',
        mode: 'fixed',
        container: null,
        resolveTarget: _fixedResolve
    });
}

export function startSourcesTutorial(): void {
    startTutorial({
        steps: sourcesTourSteps,
        overlayId: 'getting-started-overlay',
        mode: 'fixed',
        container: null,
        resolveTarget: _fixedResolve
    });
}

export function startAutomationsTutorial(): void {
    startTutorial({
        steps: automationsTutorialSteps,
        overlayId: 'getting-started-overlay',
        mode: 'fixed',
        container: null,
        resolveTarget: _fixedResolve
    });
}

export function closeTutorial(): void {
    if (!activeTutorial) return;
    const onClose = activeTutorial.onClose;
    activeTutorial.overlay.classList.remove('active');
    document.querySelectorAll('.tutorial-target').forEach(el => {
        el.classList.remove('tutorial-target');
        (el as HTMLElement).style.zIndex = '';
    });
    document.removeEventListener('keydown', handleTutorialKey);
    setActiveTutorial(null);
    if (onClose) onClose();
}

export function tutorialNext(): void {
    if (!activeTutorial) return;
    if (activeTutorial.step < activeTutorial.steps.length - 1) {
        showTutorialStep(activeTutorial.step + 1);
    } else {
        closeTutorial();
    }
}

export function tutorialPrev(): void {
    if (!activeTutorial) return;
    if (activeTutorial.step > 0) {
        showTutorialStep(activeTutorial.step - 1, -1);
    }
}

function _positionSpotlight(target: Element, overlay: HTMLElement, step: TutorialStep, index: number, isFixed: boolean): void {
    const targetRect = target.getBoundingClientRect();
    const pad = 6;
    let x, y, w, h;

    if (isFixed) {
        x = targetRect.left - pad;
        y = targetRect.top - pad;
        w = targetRect.width + pad * 2;
        h = targetRect.height + pad * 2;
    } else {
        const containerRect = activeTutorial!.container!.getBoundingClientRect();
        x = targetRect.left - containerRect.left - pad;
        y = targetRect.top - containerRect.top - pad;
        w = targetRect.width + pad * 2;
        h = targetRect.height + pad * 2;
    }

    const backdrop = overlay.querySelector('.tutorial-backdrop') as HTMLElement;
    if (backdrop) {
        backdrop.style.clipPath = `polygon(
            0% 0%, 0% 100%,
            ${x}px 100%, ${x}px ${y}px,
            ${x + w}px ${y}px, ${x + w}px ${y + h}px,
            ${x}px ${y + h}px, ${x}px 100%,
            100% 100%, 100% 0%)`;
    }

    const ring = overlay.querySelector('.tutorial-ring') as HTMLElement;
    if (ring) {
        ring.style.left = x + 'px';
        ring.style.top = y + 'px';
        ring.style.width = w + 'px';
        ring.style.height = h + 'px';
    }

    const tooltip = overlay.querySelector('.tutorial-tooltip') as HTMLElement;
    const textEl = overlay.querySelector('.tutorial-tooltip-text');
    const counterEl = overlay.querySelector('.tutorial-step-counter');
    if (textEl) textEl.textContent = t(step.textKey);
    if (counterEl) counterEl.textContent = `${index + 1} / ${activeTutorial!.steps.length}`;

    const prevBtn = overlay.querySelector('.tutorial-prev-btn') as HTMLButtonElement;
    const nextBtn = overlay.querySelector('.tutorial-next-btn');
    if (prevBtn) prevBtn.disabled = (index === 0);
    if (nextBtn) nextBtn.textContent = (index === activeTutorial!.steps.length - 1) ? '\u2713' : '\u2192';

    if (tooltip) {
        positionTutorialTooltip(tooltip, x, y, w, h, step.position, isFixed);
        tooltip.style.visibility = '';
    }
    if (ring) ring.style.visibility = '';
}

/** Wait for scroll to settle (position stops changing). */
function _waitForScrollEnd(): Promise<void> {
    return new Promise<void>(resolve => {
        let lastY = window.scrollY;
        let stableFrames = 0;
        const fallback = setTimeout(resolve, 300);
        function check() {
            const y = window.scrollY;
            if (y === lastY) stableFrames++;
            else { stableFrames = 0; lastY = y; }
            if (stableFrames >= 3) { clearTimeout(fallback); resolve(); }
            else requestAnimationFrame(check);
        }
        requestAnimationFrame(check);
    });
}

function showTutorialStep(index: number, direction: number = 1): void {
    if (!activeTutorial) return;
    activeTutorial.step = index;
    const step = activeTutorial.steps[index];
    const overlay = activeTutorial.overlay;
    const isFixed = activeTutorial.mode === 'fixed';

    document.querySelectorAll('.tutorial-target').forEach(el => {
        el.classList.remove('tutorial-target');
        (el as HTMLElement).style.zIndex = '';
    });

    const target = activeTutorial.resolveTarget(step);
    if (!target) {
        // Auto-skip hidden/missing targets in the current direction
        const next = index + direction;
        if (next >= 0 && next < activeTutorial.steps.length) showTutorialStep(next, direction);
        else closeTutorial();
        return;
    }
    target.classList.add('tutorial-target');
    if (isFixed) (target as HTMLElement).style.zIndex = '10001';

    // Scroll target into view if off-screen or behind sticky header
    const preRect = target.getBoundingClientRect();
    const headerH = isFixed ? (parseInt(getComputedStyle(document.documentElement).getPropertyValue('--header-height')) || 0) : 0;
    const needsScroll = preRect.bottom > window.innerHeight || preRect.top < headerH;

    if (needsScroll) {
        // Hide tooltip while scrolling to prevent stale position flash
        const tt = overlay.querySelector('.tutorial-tooltip') as HTMLElement | null;
        if (tt) tt.style.visibility = 'hidden';
        target.scrollIntoView({ behavior: 'smooth', block: 'center' });
        _waitForScrollEnd().then(() => {
            if (activeTutorial && activeTutorial.step === index) {
                _positionSpotlight(target, overlay, step, index, isFixed);
            }
        });
    } else {
        _positionSpotlight(target, overlay, step, index, isFixed);
    }
}

function positionTutorialTooltip(tooltip: HTMLElement, sx: number, sy: number, sw: number, sh: number, preferred: string, isFixed: boolean): void {
    const gap = 12;
    const tooltipW = 260;
    tooltip.setAttribute('style', 'left:-9999px;top:-9999px');
    const tooltipH = tooltip.offsetHeight || 150;

    const positions = {
        top:    { x: sx + sw / 2 - tooltipW / 2, y: sy - tooltipH - gap },
        bottom: { x: sx + sw / 2 - tooltipW / 2, y: sy + sh + gap },
        left:   { x: sx - tooltipW - gap, y: sy + sh / 2 - tooltipH / 2 },
        right:  { x: sx + sw + gap, y: sy + sh / 2 - tooltipH / 2 }
    };

    let pos = positions[preferred] || positions.bottom;

    const cW = isFixed ? window.innerWidth : activeTutorial!.container!.clientWidth;
    const cH = isFixed ? window.innerHeight : activeTutorial!.container!.clientHeight;

    if (pos.y + tooltipH > cH || pos.y < 0 || pos.x + tooltipW > cW || pos.x < 0) {
        const opposite = { top: 'bottom', bottom: 'top', left: 'right', right: 'left' };
        const alt = positions[opposite[preferred]];
        if (alt && alt.y >= 0 && alt.y + tooltipH <= cH && alt.x >= 0 && alt.x + tooltipW <= cW) {
            pos = alt;
        }
    }

    pos.x = Math.max(8, Math.min(cW - tooltipW - 8, pos.x));
    pos.y = Math.max(8, Math.min(cH - tooltipH - 8, pos.y));

    tooltip.setAttribute('style', `left:${Math.round(pos.x)}px;top:${Math.round(pos.y)}px`);
}

function handleTutorialKey(e: KeyboardEvent): void {
    if (!activeTutorial) return;
    if (e.key === 'Escape') { closeTutorial(); e.stopPropagation(); }
    else if (e.key === 'ArrowRight' || e.key === 'ArrowDown') { e.preventDefault(); tutorialNext(); }
    else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') { e.preventDefault(); tutorialPrev(); }
}
