import React, { useEffect, useRef, useCallback } from 'react';

// Různé barevné varianty listů
const LEAF_VARIANTS = [
    'leaf.svg',        // Původní tmavě hnědá
    'leaf-orange.svg', // Oranžová
    'leaf-yellow.svg', // Žlutá
    'leaf-red.svg',    // Červená
    'leaf-brown.svg',  // Světle hnědá
    'leaf-green.svg',  // Zelená
] as const;

interface LeafData {
    el: HTMLDivElement;
    x: number;
    y: number;
    z: number;
    rotation: {
        axis: 'X' | 'Y' | 'Z';
        value: number;
        speed: number;
        x: number;
    };
    xSpeedVariation: number;
    ySpeed: number;
    path: {
        type: number;
        start: number;
    };
    image: number;
}

interface WindOptions {
    magnitude: number;
    maxSpeed: number;
    duration: number;
    start: number;
    speed: (t: number, y: number) => number;
}

interface LeafSceneOptions {
    numLeaves: number;
    wind: WindOptions;
}

interface FallingLeavesProps {
    /** Počet padających listů (výchozí: 20) */
    numLeaves?: number;
    /** CSS třída pro kontejner (výchozí: 'falling-leaves') */
    className?: string;
    /** Barevné varianty listů k použití (výchozí: všechny) */
    leafVariants?: readonly string[];
}

class LeafScene {
    private viewport: HTMLElement;
    private world: HTMLDivElement;
    private leaves: LeafData[] = [];
    private options: LeafSceneOptions;
    private width: number;
    private height: number;
    private timer: number = 0;
    private animationId: number | null = null;
    private leafVariants: readonly string[];

    constructor(el: HTMLElement, numLeaves: number = 20, leafVariants: readonly string[] = LEAF_VARIANTS) {
        this.viewport = el;
        this.world = document.createElement('div');
        this.leafVariants = leafVariants;

        this.options = {
            numLeaves,
            wind: {
                magnitude: 1.2,
                maxSpeed: 12,
                duration: 300,
                start: 0,
                speed: () => 0
            },
        };

        this.width = this.viewport.offsetWidth;
        this.height = this.viewport.offsetHeight;
    }

    private resetLeaf = (leaf: LeafData): LeafData => {
        // place leaf towards the top left
        leaf.x = this.width * 2 - Math.random() * this.width * 1.75;
        leaf.y = -10;
        leaf.z = Math.random() * 200;

        if (leaf.x > this.width) {
            leaf.x = this.width + 10;
            leaf.y = Math.random() * this.height / 2;
        }

        // at the start, the leaf can be anywhere
        if (this.timer === 0) {
            leaf.y = Math.random() * this.height;
        }

        // Choose axis of rotation.
        // If axis is not X, chose a random static x-rotation for greater variability
        leaf.rotation.speed = Math.random() * 10;
        const randomAxis = Math.random();

        if (randomAxis > 0.5) {
            leaf.rotation.axis = 'X';
        } else if (randomAxis > 0.25) {
            leaf.rotation.axis = 'Y';
            leaf.rotation.x = Math.random() * 180 + 90;
        } else {
            leaf.rotation.axis = 'Z';
            leaf.rotation.x = Math.random() * 360 - 180;
            // looks weird if the rotation is too fast around this axis
            leaf.rotation.speed = Math.random() * 3;
        }

        // random speed
        leaf.xSpeedVariation = Math.random() * 0.8 - 0.4;
        leaf.ySpeed = Math.random() + 1.5;

        // randomly select leaf color variant
        const randomVariantIndex = Math.floor(Math.random() * this.leafVariants.length);
        leaf.image = randomVariantIndex;

        // apply the background image to the leaf element
        const leafVariant = this.leafVariants[randomVariantIndex];
        leaf.el.style.backgroundImage = `url(${leafVariant})`;

        return leaf;
    };

    private updateLeaf = (leaf: LeafData): void => {
        const leafWindSpeed = this.options.wind.speed(this.timer - this.options.wind.start, leaf.y);

        const xSpeed = leafWindSpeed + leaf.xSpeedVariation;
        leaf.x -= xSpeed;
        leaf.y += leaf.ySpeed;
        leaf.rotation.value += leaf.rotation.speed;

        const transform = `translateX(${leaf.x}px) translateY(${leaf.y}px) translateZ(${leaf.z}px) rotate${leaf.rotation.axis}(${leaf.rotation.value}deg)${leaf.rotation.axis !== 'X' ? ` rotateX(${leaf.rotation.x}deg)` : ''
            }`;

        leaf.el.style.transform = transform;

        // reset if out of view
        if (leaf.x < -10 || leaf.y > this.height + 10) {
            this.resetLeaf(leaf);
        }
    };

    private updateWind = (): void => {
        // wind follows a sine curve: asin(b*time + c) + a
        // where a = wind magnitude as a function of leaf position, b = wind.duration, c = offset
        // wind duration should be related to wind magnitude, e.g. higher windspeed means longer gust duration

        if (this.timer === 0 || this.timer > (this.options.wind.start + this.options.wind.duration)) {
            this.options.wind.magnitude = Math.random() * this.options.wind.maxSpeed;
            this.options.wind.duration = this.options.wind.magnitude * 50 + (Math.random() * 20 - 10);
            this.options.wind.start = this.timer;

            const screenHeight = this.height;

            this.options.wind.speed = function (t: number, y: number) {
                // should go from full wind speed at the top, to 1/2 speed at the bottom, using leaf Y
                const a = this.magnitude / 2 * (screenHeight - 2 * y / 3) / screenHeight;
                return a * Math.sin(2 * Math.PI / this.duration * t + (3 * Math.PI / 2)) + a;
            };
        }
    };

    public init = (): void => {
        // Clear existing leaves
        this.leaves = [];
        this.world.innerHTML = '';

        for (let i = 0; i < this.options.numLeaves; i++) {
            const leaf: LeafData = {
                el: document.createElement('div'),
                x: 0,
                y: 0,
                z: 0,
                rotation: {
                    axis: 'X',
                    value: 0,
                    speed: 0,
                    x: 0
                },
                xSpeedVariation: 0,
                ySpeed: 0,
                path: {
                    type: 1,
                    start: 0,
                },
                image: 1
            };

            this.resetLeaf(leaf);
            this.leaves.push(leaf);
            this.world.appendChild(leaf.el);
        }

        this.world.className = 'leaf-scene';
        this.viewport.appendChild(this.world);

        // set perspective
        this.world.style.perspective = "400px";

        // reset window height/width on resize
        const handleResize = (): void => {
            this.width = this.viewport.offsetWidth;
            this.height = this.viewport.offsetHeight;
        };

        window.addEventListener('resize', handleResize);
    };

    public render = (): void => {
        this.updateWind();

        for (let i = 0; i < this.leaves.length; i++) {
            this.updateLeaf(this.leaves[i]);
        }

        this.timer++;
        this.animationId = requestAnimationFrame(this.render);
    };

    public destroy = (): void => {
        if (this.animationId) {
            cancelAnimationFrame(this.animationId);
            this.animationId = null;
        }

        if (this.world && this.world.parentNode) {
            this.world.parentNode.removeChild(this.world);
        }

        window.removeEventListener('resize', () => {
            this.width = this.viewport.offsetWidth;
            this.height = this.viewport.offsetHeight;
        });
    };
}

/**
 * Komponenta pro zobrazení padajících listů na pozadí stránky
 * 
 * @param numLeaves - Počet padajících listů (výchozí: 20)
 * @param className - CSS třída pro kontejner (výchozí: 'falling-leaves')
 * @param leafVariants - Barevné varianty listů k použití (výchozí: všechny)
 * 
 * @example
 * // Základní použití s výchozím počtem listů
 * <FallingLeaves />
 * 
 * @example  
 * // Použití s vlastním počtem listů
 * <FallingLeaves numLeaves={50} />
 * 
 * @example
 * // Použití s vlastní CSS třídou a pouze podzimními barvami
 * <FallingLeaves 
 *   numLeaves={15} 
 *   className="autumn-leaves"
 *   leafVariants={['leaf-orange.svg', 'leaf-red.svg', 'leaf-yellow.svg']}
 * />
 */
const FallingLeaves: React.FC<FallingLeavesProps> = ({
    numLeaves = 20,
    className = 'falling-leaves',
    leafVariants = LEAF_VARIANTS
}) => {
    const containerRef = useRef<HTMLDivElement>(null);
    const leafSceneRef = useRef<LeafScene | null>(null);

    const initializeLeafScene = useCallback(() => {
        if (containerRef.current) {
            leafSceneRef.current = new LeafScene(containerRef.current, numLeaves, leafVariants);
            leafSceneRef.current.init();
            leafSceneRef.current.render();
        }
    }, [numLeaves, leafVariants]);

    useEffect(() => {
        initializeLeafScene();

        return () => {
            if (leafSceneRef.current) {
                leafSceneRef.current.destroy();
                leafSceneRef.current = null;
            }
        };
    }, [initializeLeafScene]);

    return <div ref={containerRef} className={className} />;
};

// Přednastavení pro různé účely
export const LEAF_PRESETS = {
    LIGHT: 10,      // Lehký podzimní efekt
    NORMAL: 20,     // Standardní množství  
    HEAVY: 40,      // Silný podzimní vítr
    BLIZZARD: 80    // Hustý pád listí
} as const;

// Přednastavené barevné kombinace
export const LEAF_COLOR_THEMES = {
    ALL: LEAF_VARIANTS,                                          // Všechny barvy
    AUTUMN: ['leaf-orange.svg', 'leaf-red.svg', 'leaf-yellow.svg', 'leaf-brown.svg'] as const, // Podzimní barvy
    WARM: ['leaf-orange.svg', 'leaf-red.svg', 'leaf-brown.svg'] as const,           // Teplé barvy
    CLASSIC: ['leaf.svg', 'leaf-brown.svg'] as const,                               // Klasické hnědé odstíny
    BRIGHT: ['leaf-yellow.svg', 'leaf-orange.svg'] as const,                        // Světlé barvy
} as const;

export default FallingLeaves;