// Spirit of Christmas Effect for Seazonify Controller
// The ultimate full-vibe preset: Soft snowfall, crystal flakes, garlands, aurora, and a realistic "zigzag" galloping Santa sleigh dropping giant gifts.
// Compatible with SeazonifyController.injectVisualEffect()
// Usage: SeazonifyController.injectVisualEffect(spiritOfChristmasEffect);

const spiritOfChristmasEffect = {
    name: "Spirit of Christmas",
    description: "The ultimate full-vibe preset. Snowfall, garlands, aurora, and a realistic galloping Santa team dropping giant gifts.",
    icon: "🎄",
    type: "visual",
    author: "Md Mim Akhtar",
    icon: "🎄",
    thumbnail: "assets/effects/visual/thumbnails/spirit-of-christmas.webp",
    version: "1.0.0",
    license: "https://seazonify.com/license",
    created: "2026-01-20",
    category: "winter",
    tags: ["christmas", "winter", "snow", "snowflakes", "aurora", "holiday", "sleigh", "santa", "cozy", "magical", "garlands", "lights", "gifts"],
    css: `
    .szfy-christmas-container {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      pointer-events: none;
      z-index: 9999;
      overflow: hidden;
    }

    /* Aurora */
    .szfy-aurora-overlay {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 60%;
      background: linear-gradient(180deg, 
        rgba(0, 255, 128, 0.0) 0%, 
        rgba(0, 255, 136, 0.03) 20%, 
        rgba(100, 50, 255, 0.03) 50%, 
        rgba(0, 0, 0, 0) 100%);
      filter: blur(50px);
      animation: szfy-aurora-shift 25s infinite alternate ease-in-out;
      opacity: 0.5;
    }

    @keyframes szfy-aurora-shift {
      0% { transform: scaleX(1.0); opacity: 0.3; }
      50% { transform: scaleX(1.1); opacity: 0.6; }
      100% { transform: scaleX(1.05); opacity: 0.4; }
    }

    /* Snow */
    .szfy-snowflake {
      position: absolute;
      top: -20px;
      pointer-events: none;
      will-change: transform;
      user-select: none;
    }
    .szfy-snowflake.dot {
      border-radius: 50%;
      background: white;
      opacity: 0.9;
      filter: blur(0.3px);
      box-shadow: 0 0 3px rgba(255,255,255,0.6);
    }
    .szfy-snowflake.dot.large { width: 4.5px; height: 4.5px; filter: blur(0.5px); }
    .szfy-snowflake.dot.medium { width: 3px; height: 3px; }
    .szfy-snowflake.dot.small { width: 2px; height: 2px; opacity: 0.7; }
    .szfy-snowflake.detailed {
      color: white;
      background: transparent;
      box-shadow: none;
      filter: drop-shadow(0 0 2px rgba(255,255,255,0.8));
      line-height: 1;
      opacity: 0.85;
      font-family: sans-serif;
    }

    /* Garlands */
    .szfy-garland-top, .szfy-garland-left, .szfy-garland-right {
      position: absolute;
      pointer-events: none;
      display: flex;
    }
    .szfy-garland-top { top: -2px; left: 0; width: 100%; height: 30px; justify-content: space-around; align-items: flex-start; padding-top: 5px; }
    .szfy-garland-left { top: 0; left: 6px; width: 20px; height: 100%; flex-direction: column; justify-content: space-around; align-items: center; }
    .szfy-garland-right { top: 0; right: 6px; width: 20px; height: 100%; flex-direction: column; justify-content: space-around; align-items: center; }
    
    .szfy-garland-light {
      width: 8px; height: 8px; border-radius: 50%; background: #fff;
      box-shadow: 0 0 10px 4px rgba(255, 255, 255, 0.4); 
      animation: szfy-twinkle 4s infinite ease-in-out alternate;
    }
    .szfy-garland-light:nth-child(4n) { background: #ff5f5f; box-shadow: 0 0 12px 3px rgba(255, 95, 95, 0.4); animation-duration: 4.5s; }
    .szfy-garland-light:nth-child(4n+1) { background: #5fff5f; box-shadow: 0 0 12px 3px rgba(95, 255, 95, 0.4); animation-duration: 3.0s; }
    .szfy-garland-light:nth-child(4n+2) { background: #ffff80; box-shadow: 0 0 12px 3px rgba(255, 255, 128, 0.4); animation-duration: 5.0s; }
    .szfy-garland-light:nth-child(4n+3) { background: #80e5ff; box-shadow: 0 0 12px 3px rgba(128, 229, 255, 0.4); animation-duration: 3.5s; }
    
    @keyframes szfy-twinkle {
      0% { opacity: 0.6; transform: scale(0.9); }
      100% { opacity: 1; transform: scale(1.1); box-shadow: 0 0 15px 5px currentColor; }
    }

    /* Sleigh Group */
    .szfy-sleigh-group {
      position: absolute;
      display: flex;
      align-items: center;
      gap: 0px; /* Reduced gap to keep team tighter */
      font-size: 42px; 
      filter: drop-shadow(0 0 10px rgba(255, 215, 0, 0.3));
      transform: scaleX(-1); /* Face right */
      will-change: transform, left, top;
      z-index: 10000;
      white-space: nowrap;
    }

    .szfy-reindeer {
      display: inline-block;
      position: relative;
      transform-origin: bottom center;
    }

    /* Zigzag Running Logic */
    /* Odd deer LEAP */
    .szfy-reindeer.leap {
      animation: szfy-gallop-leap 0.4s infinite alternate ease-in-out;
    }

    /* Even deer LAND */
    .szfy-reindeer.land {
      animation: szfy-gallop-land 0.4s infinite alternate ease-in-out;
      animation-delay: 0.2s; /* Syncopated */
    }

    .szfy-sleigh-cab {
      display: inline-block;
      margin-left: 15px;
      animation: szfy-sleigh-bob 2s infinite ease-in-out;
    }

    @keyframes szfy-gallop-leap {
      0% { transform: translateY(0) rotate(0deg) skewX(0deg); }
      100% { transform: translateY(-8px) rotate(-10deg) skewX(-5deg); } /* Leap up and forward tilt */
    }

    @keyframes szfy-gallop-land {
      0% { transform: translateY(0) rotate(0deg) skewX(0deg); }
      100% { transform: translateY(3px) rotate(5deg) skewX(5deg); } /* Compress down and back tilt */
    }

    @keyframes szfy-sleigh-bob {
      0%, 100% { transform: translateY(0) rotate(0deg); }
      50% { transform: translateY(4px) rotate(-1deg); }
    }

    /* Giant Falling Gift */
    .szfy-gift {
      position: absolute;
      font-size: 48px; /* Bigger Gift! */
      z-index: 9998;
      will-change: transform, top;
      filter: drop-shadow(0 4px 8px rgba(0,0,0,0.3));
    }
    
    /* Celebration */
    .szfy-open-gift-burst { position: absolute; padding-left: 20px; z-index: 9999; } /* Center visual adjustment */
    
    .szfy-particle {
      position: absolute;
      width: 8px; /* Bigger particles */
      height: 8px;
      border-radius: 50%;
      opacity: 0;
      animation: szfy-explode 1s ease-out forwards;
    }

    @keyframes szfy-explode {
        0% { transform: translate(0,0) scale(1); opacity: 1; }
        100% { transform: translate(var(--tx), var(--ty)) scale(0); opacity: 0; }
    }

    .szfy-magic-glow {
        position: absolute;
        width: 100px; /* Bigger glow */
        height: 100px;
        background: radial-gradient(circle, rgba(255,255,200,1) 0%, rgba(255,215,0,0) 70%);
        transform: translate(-50%, -50%);
        animation: szfy-glow-pop 0.8s ease-out forwards;
    }
    
    @keyframes szfy-glow-pop {
        0% { opacity: 0; transform: translate(-50%, -50%) scale(0.5); }
        50% { opacity: 0.8; transform: translate(-50%, -50%) scale(1.2); }
        100% { opacity: 0; transform: translate(-50%, -50%) scale(1.5); }
    }
    `,
    html: `
    <div class="szfy-christmas-container" id="szfy-christmas-container">
      <div class="szfy-aurora-overlay"></div>
      <div class="szfy-garland-top" id="szfy-garland-top"></div>
      <div class="szfy-garland-left" id="szfy-garland-left"></div>
      <div class="szfy-garland-right" id="szfy-garland-right"></div>
      <div id="szfy-gifts-container"></div>
    </div>
  `,
    js: `
    (function() {
      // Safety: Cleanup any prior instance if the controller logic didn't catch it
      if (typeof window.szfySpiritCleanup === 'function') {
          window.szfySpiritCleanup();
      }
      
      // Double Safety: Check for global audio and kill it
      if (window.szfySleighAudio) {
          window.szfySleighAudio.pause();
          window.szfySleighAudio = null;
      }

      const container = document.getElementById('szfy-christmas-container');
      const giftsContainer = document.getElementById('szfy-gifts-container');
      if (!container) return;
      
      // DOM Watchdog: If the container is removed from DOM OR hidden, handle it.
      const watchdogInterval = setInterval(() => {
          // 1. Removal Check
          if (!document.body.contains(container)) {
              if (window.szfySpiritCleanup) window.szfySpiritCleanup();
              return;
          }
          
          // 2. Visibility Check (If toggle just hides it)
          // refined: getComputedStyle might report 'block' even if parent is hidden. 
          // offsetWidth/Height is safer. display:none parent => 0x0 size child.
          const isHidden = (container.offsetWidth === 0 && container.offsetHeight === 0);
          
          if (isHidden) {
              // If hidden, confirm audio is paused
              if (window.szfySleighAudio && !window.szfySleighAudio.paused) {
                  window.szfySleighAudio.pause();
              }
          }
      }, 1000);

      const maxSnowflakes = 80;
      const snowflakes = [];
      let animationId = null;
      let lastTime = 0;
      
      let sleighTimer = null;
      let sleighElement = null;
      let sleighActive = false;
      
      // Audio
      const audioUrl = 'assets/effects/visual/assets/mp3/asset-1768917839432.mp3';
      
      // Use global to track it across re-injections if needed
      if (!window.szfySleighAudio) {
          window.szfySleighAudio = new Audio(audioUrl);
          window.szfySleighAudio.loop = true;
          window.szfySleighAudio.volume = 0;
      }
      let sleighAudio = window.szfySleighAudio;
      let fadeInterval = null;

      function fadeAudio(targetVolume, duration, onComplete) {
         if (fadeInterval) clearInterval(fadeInterval);
         const startVolume = sleighAudio.volume;
         const diff = targetVolume - startVolume;
         const steps = 20;
         const stepTime = duration / steps;
         const volumeStep = diff / steps;
         let currentStep = 0;

         fadeInterval = setInterval(() => {
             currentStep++;
             let newVol = startVolume + (volumeStep * currentStep);
             // Clamp
             if (newVol < 0) newVol = 0;
             if (newVol > 1) newVol = 1;
             sleighAudio.volume = newVol;

             if (currentStep >= steps) {
                 clearInterval(fadeInterval);
                 fadeInterval = null;
                 if (onComplete) onComplete();
             }
         }, stepTime);
      }

      // === 1. Lights ===
      function createLights(targetId, direction) {
        const target = document.getElementById(targetId);
        if (!target) return;
        target.innerHTML = ''; 
        const fragment = document.createDocumentFragment();
        let count = direction === 'horizontal' ? Math.floor(window.innerWidth / 40) : Math.floor(window.innerHeight / 40);
        for (let i = 0; i < count; i++) {
          const light = document.createElement('div');
          light.className = 'szfy-garland-light';
          light.style.animationDelay = (Math.random() * 3) + 's';
          if (direction === 'horizontal') {
             const yOffset = Math.sin((i / count) * Math.PI * 4) * 5; 
             light.style.transform = \`translateY(\${ yOffset }px)\`;
          } else {
             light.style.transform = 'translateX(0)';
          }
          fragment.appendChild(light);
        }
        target.appendChild(fragment);
      }
      function initGarlands() {
          createLights('szfy-garland-top', 'horizontal');
          createLights('szfy-garland-left', 'vertical');
          createLights('szfy-garland-right', 'vertical');
      }

      // === 2. Snow ===
      class Snowflake {
        constructor() {
          this.element = document.createElement('div');
          this.reset(true); 
        }
        reset(initial = false) {
            const isDetailed = Math.random() < 0.25;
            this.element.removeAttribute('style');
            if (isDetailed) {
                const chars = ['❄', '❅', '❆'];
                this.element.innerText = chars[Math.floor(Math.random() * chars.length)];
                this.element.className = 'szfy-snowflake detailed';
                this.element.style.fontSize = (Math.random() * 10 + 10) + 'px';
                this.rotation = Math.random() * 360;
                this.rotationSpeed = (Math.random() - 0.5) * 2;
            } else {
                this.element.innerText = '';
                const types = ['small', 'medium', 'medium', 'large'];
                this.element.className = \`szfy-snowflake dot \${types[Math.floor(Math.random() * types.length)]}\`;
                this.rotation = 0;
                this.rotationSpeed = 0;
            }
            this.x = Math.random() * window.innerWidth;
            this.y = initial ? Math.random() * window.innerHeight : -30;
            this.speed = 0.5 + Math.random() * 1.5; 
            this.swaySpeed = 0.02 + Math.random() * 0.05;
            this.swayOffset = Math.random() * Math.PI * 2;
            this.radius = Math.random() * 20 + 5; 
            if (!this.element.parentNode) container.appendChild(this.element);
            this.updatePosition();
        }
        updatePosition() {
            const sway = Math.sin(this.swayOffset) * this.radius;
            let transform = \`translate3d(\${this.x + sway}px, \${this.y}px, 0)\`;
            if (this.rotationSpeed !== 0) transform += \` rotate(\${this.rotation}deg)\`;
            this.element.style.transform = transform;
        }
        update(deltaTime) {
            this.y += this.speed * (deltaTime * 0.06); 
            this.swayOffset += this.swaySpeed * (deltaTime * 0.06); 
            this.rotation += this.rotationSpeed * (deltaTime * 0.06);
            if (this.y > window.innerHeight + 30) this.reset(); else this.updatePosition();
        }
        destroy() { if (this.element.parentNode) this.element.parentNode.removeChild(this.element); }
      }
      function initSnow() { for(let i=0; i<maxSnowflakes; i++) snowflakes.push(new Snowflake()); }

      // === 3. Gift Drop ===
      function celebrateGift(x, y) {
        const burst = document.createElement('div');
        burst.className = 'szfy-open-gift-burst';
        burst.style.left = x + 'px';
        burst.style.top = y + 'px';
        
        const glow = document.createElement('div');
        glow.className = 'szfy-magic-glow';
        burst.appendChild(glow);

        const colors = ['#ff4d4d', '#4dff4d', '#ffff4d', '#ffffff', '#80e5ff'];
        for(let i=0; i<16; i++) { // More particles for bigger gift
            const p = document.createElement('div');
            p.className = 'szfy-particle';
            p.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
            const angle = (Math.random() * 360) * (Math.PI / 180);
            const dist = 50 + Math.random() * 60; // Wider burst
            const tx = Math.cos(angle) * dist;
            const ty = Math.sin(angle) * dist;
            p.style.setProperty('--tx', \`\${tx}px\`);
            p.style.setProperty('--ty', \`\${ty}px\`);
            burst.appendChild(p);
        }
        giftsContainer.appendChild(burst);
        setTimeout(() => { if (burst.parentNode) burst.parentNode.removeChild(burst); }, 1200);
      }

      function dropGift(startX, startY) {
          const gift = document.createElement('div');
          gift.className = 'szfy-gift';
          gift.innerText = '🎁';
          gift.style.left = startX + 'px';
          gift.style.top = startY + 'px';
          giftsContainer.appendChild(gift);

          let y = startY;
          let velocity = 2;
          const gravity = 0.4; // Heavier feel
          const floor = window.innerHeight - 60; 

          function animateDrop() {
              if (y < floor) {
                  y += velocity;
                  velocity += gravity;
                  gift.style.top = y + 'px';
                  requestAnimationFrame(animateDrop);
              } else {
                  celebrateGift(startX + 16, y); // Adjust center
                  if (gift.parentNode) gift.parentNode.removeChild(gift);
              }
          }
          requestAnimationFrame(animateDrop);
      }

      // === 4. Sleigh ===
      function spawnSleigh() {
        if (sleighActive) return;

        // Visibility Check: Don't spawn if hidden
        // This prevents "Ghost Sleighs" if the effect is toggled off (hidden) but script is running
        if (container.offsetWidth === 0 && container.offsetHeight === 0) {
             // Just reschedule check later
             scheduleSleigh(); 
             return; 
        }

        sleighActive = true;
        
        // Start Audio
        if (sleighAudio) {
            sleighAudio.volume = 0;
            sleighAudio.play().catch(e => { /* Auto-play might be blocked */ });
            fadeAudio(0.5, 2000);
        }
        let isFadingOut = false;

        const group = document.createElement('div');
        group.className = 'szfy-sleigh-group';
        
        // Randomize direction: 0 = Left->Right, 1 = Right->Left
        const direction = Math.random() < 0.5 ? 1 : -1; // 1: L->R, -1: R->L

        // 4 Reindeer + Sleigh
        group.innerHTML = \`
           <span class="szfy-reindeer leap">🦌</span>
           <span class="szfy-reindeer land">🦌</span>
           <span class="szfy-reindeer leap">🦌</span>
           <span class="szfy-reindeer land">🦌</span>
           <span class="szfy-sleigh-cab">🛷🎅</span>
\`;
        
        // Flip if R->L (natural emoji is Left-facing? No, usually emojis face Left. 
        // Wait: Sleigh emoji 🛷 faces Left usually. Deer 🦌 faces Left.
        // Original code: transform: scaleX(-1); /* Face right */ -> this means emojis face LEFT natively.
        // So L->R (moving Right) needs scaleX(-1).
        // R->L (moving Left) needs scaleX(1).
        
        group.style.transform = direction === 1 ? 'scaleX(-1)' : 'scaleX(1)';

        const startY = winHeight => 50 + Math.random() * (winHeight / 3);
        let posY = startY(window.innerHeight);
        
        // Start position
        let posX = direction === 1 ? -500 : window.innerWidth + 500;
        
        const speed = 3 + Math.random();
        const speedX = direction * speed; 
        
        const width = window.innerWidth;
        let totalGifts = 1;

        if (width < 768) {
            totalGifts = 1; // Mobile: Always 1
        } else if (width < 1024) {
            totalGifts = Math.floor(Math.random() * 2) + 1; // Tablet: 1 or 2
        } else {
            totalGifts = Math.floor(Math.random() * 3) + 1; // Desktop: 1, 2, or 3
        }
        const dropPositions = []; 
        
        for(let i=0; i<totalGifts; i++) {
           const zone = width / totalGifts;
           dropPositions.push((i * zone) + Math.random() * (zone * 0.8));
        }
        
        // Sort for L->R (Ascending), Sort for R->L (Descending)
        if (direction === 1) {
            dropPositions.sort((a,b) => a - b);
        } else {
            dropPositions.sort((a,b) => b - a);
        }

        container.appendChild(group);
        sleighElement = group;
        let time = 0;

        function animateSleigh() {
           if (!sleighActive || !sleighElement) return;
           posX += speedX;
           const wave = Math.sin(time * 0.003) * 40; 
           
           // We apply the translation AND the static scale for direction
           const dirScale = direction === 1 ? -1 : 1;
           sleighElement.style.transform = \`translate3d(\${ posX }px, \${ posY + wave}px, 0) scaleX(\${ dirScale })\`;
           
           // Audio fade out check
           // L->R: exiting screen at width
           // R->L: exiting screen at 0
           if (!isFadingOut) {
               const exiting = direction === 1 ? (posX > window.innerWidth) : (posX + 400 < 0); 
               // Note: Sleigh width approx 300-400px. For R->L, we want to start fade when it STARTS exiting or is fully off?
               // User said "As santa goes completely fade out sound".
               // If it's R->L, it moves towards negative. 
               // Let's fade when it hits the edge (0).
               const checkExit = direction === 1 ? (posX > window.innerWidth) : (posX < -200);
               
               if (checkExit) {
                   isFadingOut = true;
                   fadeAudio(0, 2000, () => {
                       sleighAudio.pause();
                   });
               }
           }

           // Drop Logic
           if (dropPositions.length > 0) {
               let shouldDrop = false;
               if (direction === 1) { // Moving Right
                   if (posX > dropPositions[0]) shouldDrop = true;
               } else { // Moving Left
                   if (posX < dropPositions[0]) shouldDrop = true;
               }

                if (shouldDrop) {
                    // Adjust drop position for R->L to align with Sleigh at the back
                    const dropOffset = direction === 1 ? 0 : 180; 
                    dropGift(posX + dropOffset, posY + wave + 25); 
                    dropPositions.shift();
                }
           }

           time += 16; 
           
           // Cleanup bounds
           const outOfBounds = direction === 1 ? (posX > window.innerWidth + 500) : (posX < -600);
           
           if (outOfBounds) { 
               cleanupSleigh(); 
           } else { 
               requestAnimationFrame(animateSleigh); 
           }
        }
        requestAnimationFrame(animateSleigh);
      }

      function cleanupSleigh() {
        sleighActive = false;
        if (sleighElement && sleighElement.parentNode) sleighElement.parentNode.removeChild(sleighElement);
        sleighElement = null;
        scheduleSleigh(); 
      }

      function scheduleSleigh() {
          const delay = 8000 + Math.random() * 15000;
          sleighTimer = setTimeout(spawnSleigh, delay);
      }

      function animate(currentTime) {
        if (!lastTime) lastTime = currentTime;
        const deltaTime = currentTime - lastTime;
        lastTime = currentTime;
        snowflakes.forEach(f => f.update(deltaTime));
        animationId = requestAnimationFrame(animate);
      }
      
      function handleResize() { initGarlands(); }

      initGarlands();
      initSnow();
      scheduleSleigh();
      animationId = requestAnimationFrame(animate);
      window.addEventListener('resize', handleResize);

      window.szfySpiritCleanup = function() {
        if (animationId) cancelAnimationFrame(animationId);
        if (sleighTimer) clearTimeout(sleighTimer);
        
        // Kill active sleigh cycle
        sleighActive = false;
        sleighElement = null; 
        if (fadeInterval) clearInterval(fadeInterval);
        if (watchdogInterval) clearInterval(watchdogInterval);
        
        snowflakes.forEach(f => f.destroy());
        snowflakes.length = 0;
        
        // Remove sleigh element if it exists in DOM (redundant check if sleighElement is nullified but good for safety if ref exists)
        // Actually we nullified the variable so we can't use it to remove.
        // But we can query the group class or ensure checking parentNode before nullifying.
        // Let's use the class query to be sure we clean up.
        const activeSleigh = container ? container.querySelector('.szfy-sleigh-group') : null;
        if (activeSleigh) activeSleigh.parentNode.removeChild(activeSleigh);

        if (giftsContainer) giftsContainer.innerHTML = '';
        if (container) container.innerHTML = '';
        if (sleighAudio) { 
            sleighAudio.pause(); 
            sleighAudio.currentTime = 0; 
            sleighAudio = null; // Break local reference
        }
        if (window.szfySleighAudio) { window.szfySleighAudio.pause(); window.szfySleighAudio = null; }
        window.removeEventListener('resize', handleResize);
      };
    })();
    `
};

if (typeof window !== 'undefined' && window.SeazonifyController) {
    window.SeazonifyController.injectVisualEffect(spiritOfChristmasEffect);
}
if (typeof module !== 'undefined' && module.exports) {
    module.exports = { visual: spiritOfChristmasEffect };
}