/**
 * Viewport Controls Component
 *
 * Floating +/- zoom buttons and fit-to-view for touch devices.
 * Positioned bottom-right by default (mobile convention).
 * Auto-shown on touch devices, hidden on mouse-primary.
 */

import React, { useState } from 'react';
import { useAtom, useAtomValue, useSetAtom } from 'jotai';
import { zoomAtom, panAtom, resetViewportAtom } from '../core/viewport-store';
import { isTouchDeviceAtom } from '../core/input-store';

export interface ViewportControlsProps {
    /** Minimum zoom level. Default: 0.1 */
    minZoom?: number;
    /** Maximum zoom level. Default: 5 */
    maxZoom?: number;
    /** Zoom step per button press. Default: 0.25 */
    zoomStep?: number;
    /** Position of controls. Default: 'bottom-right' */
    position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
    /** Always visible (even on mouse devices). Default: false */
    alwaysVisible?: boolean;
    /** Custom class name */
    className?: string;
    /** Custom styles for the container */
    style?: React.CSSProperties;
}

/**
 * Floating viewport controls (zoom in/out, reset).
 * Shown by default only on touch devices.
 */
export function ViewportControls({
    minZoom = 0.1,
    maxZoom = 5,
    zoomStep = 0.25,
    position = 'bottom-right',
    alwaysVisible = false,
    className,
    style,
}: ViewportControlsProps) {
    const [zoom, setZoom] = useAtom(zoomAtom);
    const [pan, setPan] = useAtom(panAtom);
    const isTouchDevice = useAtomValue(isTouchDeviceAtom);
    const resetViewport = useSetAtom(resetViewportAtom);

    const handleZoomIn = () => {
        setZoom(Math.min(maxZoom, zoom + zoomStep));
    };

    const handleZoomOut = () => {
        setZoom(Math.max(minZoom, zoom - zoomStep));
    };

    const handleReset = () => {
        resetViewport();
    };

    // Hide on mouse-primary devices unless forced visible
    if (!alwaysVisible && !isTouchDevice) {
        return null;
    }

    const positionStyles = getPositionStyles(position);
    const zoomPercent = Math.round(zoom * 100);

    return (
        <div
            className={className}
            style={{
                position: 'absolute',
                ...positionStyles,
                display: 'flex',
                flexDirection: 'column',
                gap: '4px',
                zIndex: 100,
                pointerEvents: 'auto',
                ...style,
            }}
        >
            <ControlButton
                onClick={handleZoomIn}
                disabled={zoom >= maxZoom}
                aria-label="Zoom in"
            >
                <PlusIcon />
            </ControlButton>

            <ControlButton
                onClick={handleReset}
                aria-label={`Reset zoom (${zoomPercent}%)`}
                title={`${zoomPercent}%`}
                style={{ fontSize: '10px', fontWeight: 600 }}
            >
                {zoomPercent}%
            </ControlButton>

            <ControlButton
                onClick={handleZoomOut}
                disabled={zoom <= minZoom}
                aria-label="Zoom out"
            >
                <MinusIcon />
            </ControlButton>
        </div>
    );
}

// =============================================================================
// Internal Components
// =============================================================================

interface ControlButtonProps extends React.ComponentPropsWithoutRef<'button'> { }

function ControlButton({ children, style, disabled, onClick, ...props }: ControlButtonProps) {
    const [pulsing, setPulsing] = useState(false);

    const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
        if (!disabled) {
            setPulsing(true);
        }
        onClick?.(e);
    };

    return (
        <button
            {...props}
            disabled={disabled}
            className={pulsing ? 'canvas-tap-pulse' : undefined}
            onAnimationEnd={() => setPulsing(false)}
            onClick={handleClick}
            style={{
                width: '44px',
                height: '44px',
                borderRadius: '12px',
                border: '1px solid var(--canvas-control-border, rgba(255,255,255,0.1))',
                backgroundColor: 'var(--canvas-control-bg, rgba(30,30,30,0.85))',
                color: 'var(--canvas-control-fg, rgba(255,255,255,0.9))',
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'center',
                cursor: disabled ? 'default' : 'pointer',
                opacity: disabled ? 0.4 : 1,
                touchAction: 'manipulation',
                WebkitTapHighlightColor: 'transparent',
                userSelect: 'none',
                transition: 'background-color 150ms, opacity 150ms',
                backdropFilter: 'blur(12px)',
                WebkitBackdropFilter: 'blur(12px)',
                padding: 0,
                ...style,
            }}
            data-no-drag="true"
        >
            {children}
        </button>
    );
}

function PlusIcon() {
    return (
        <svg width="18" height="18" viewBox="0 0 18 18" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
            <line x1="9" y1="4" x2="9" y2="14" />
            <line x1="4" y1="9" x2="14" y2="9" />
        </svg>
    );
}

function MinusIcon() {
    return (
        <svg width="18" height="18" viewBox="0 0 18 18" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
            <line x1="4" y1="9" x2="14" y2="9" />
        </svg>
    );
}

function getPositionStyles(position: string): React.CSSProperties {
    switch (position) {
        case 'bottom-right':
            return { bottom: 'max(16px, env(safe-area-inset-bottom, 16px))', right: 'max(16px, env(safe-area-inset-right, 16px))' };
        case 'bottom-left':
            return { bottom: 'max(16px, env(safe-area-inset-bottom, 16px))', left: 'max(16px, env(safe-area-inset-left, 16px))' };
        case 'top-right':
            return { top: 'max(16px, env(safe-area-inset-top, 16px))', right: 'max(16px, env(safe-area-inset-right, 16px))' };
        case 'top-left':
            return { top: 'max(16px, env(safe-area-inset-top, 16px))', left: 'max(16px, env(safe-area-inset-left, 16px))' };
        default:
            return { bottom: 'max(16px, env(safe-area-inset-bottom, 16px))', right: 'max(16px, env(safe-area-inset-right, 16px))' };
    }
}
