/**
 * NativeProvider - Lightweight native HTML5 video player
 * For demo videos, background videos, autoplay loop muted scenarios
 */

'use client';

import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';

import { cn } from '@djangocfg/ui-core/lib';
import { Preloader, AspectRatio } from '@djangocfg/ui-core';
import { useVideoPlayerSettings } from '../hooks/useVideoPlayerSettings';

import type { NativeProviderProps, VideoPlayerRef } from '../types';
import { videoDebug } from '../utils/debug';

/**
 * Get video URL from source
 */
function getVideoUrl(source: NativeProviderProps['source']): string {
  switch (source.type) {
    case 'url':
      return source.url;
    case 'data-url':
      return source.data;
    default:
      return '';
  }
}

export const NativeProvider = forwardRef<VideoPlayerRef, NativeProviderProps>(
  (
    {
      source,
      aspectRatio = 16 / 9,
      autoPlay = true,
      muted = true,
      loop = true,
      playsInline = true,
      preload = 'auto',
      controls = false,
      disableContextMenu = true,
      showPreloader = true,
      preloaderTimeout = 5000,
      className,
      videoClassName,
      onPlay,
      onPause,
      onEnded,
      onError,
      onLoadStart,
      onCanPlay,
      onTimeUpdate,
    },
    ref
  ) => {
    const [isLoading, setIsLoading] = useState(showPreloader);
    const videoRef = useRef<HTMLVideoElement>(null);

    // Persisted player settings
    const { settings: savedSettings, updateVolume } = useVideoPlayerSettings();

    const videoUrl = getVideoUrl(source);

    // Debug: Log video source
    useEffect(() => {
      videoDebug.load(videoUrl, source.type);
    }, [videoUrl, source.type]);

    // Expose video element methods via ref
    useImperativeHandle(
      ref,
      () => ({
        play: () => videoRef.current?.play(),
        pause: () => videoRef.current?.pause(),
        togglePlay: () => {
          const video = videoRef.current;
          if (video) {
            video.paused ? video.play() : video.pause();
          }
        },
        seekTo: (time: number) => {
          if (videoRef.current) videoRef.current.currentTime = time;
        },
        setVolume: (volume: number) => {
          if (videoRef.current) videoRef.current.volume = Math.max(0, Math.min(1, volume));
        },
        toggleMute: () => {
          if (videoRef.current) videoRef.current.muted = !videoRef.current.muted;
        },
        enterFullscreen: () => videoRef.current?.requestFullscreen(),
        exitFullscreen: () => document.exitFullscreen(),
        get currentTime() {
          return videoRef.current?.currentTime ?? 0;
        },
        get duration() {
          return videoRef.current?.duration ?? 0;
        },
        get paused() {
          return videoRef.current?.paused ?? true;
        },
      }),
      []
    );

    useEffect(() => {
      if (!showPreloader) return;

      const video = videoRef.current;
      if (!video) return;

      // Check if video is already loaded
      if (video.readyState >= 3) {
        setIsLoading(false);
        return;
      }

      const hideLoader = () => setIsLoading(false);

      video.addEventListener('canplay', hideLoader);
      video.addEventListener('loadeddata', hideLoader);
      video.addEventListener('playing', hideLoader);

      // Fallback: hide loader after timeout
      const timeout = setTimeout(hideLoader, preloaderTimeout);

      return () => {
        video.removeEventListener('canplay', hideLoader);
        video.removeEventListener('loadeddata', hideLoader);
        video.removeEventListener('playing', hideLoader);
        clearTimeout(timeout);
      };
    }, [showPreloader, preloaderTimeout]);

    // Debug: Log video events
    useEffect(() => {
      const video = videoRef.current;
      if (!video) return;

      const handleLoadedMetadata = () => {
        videoDebug.state('loadedmetadata', { duration: video.duration });
      };

      const handleCanPlayDebug = () => {
        videoDebug.state('canplay', { duration: video.duration, buffered: video.buffered.length });
        videoDebug.buffer(video.buffered, video.duration);
        // Apply saved volume
        video.volume = savedSettings.volume;
      };

      const handleSeeking = () => {
        videoDebug.event('seeking', { currentTime: video.currentTime });
      };

      const handleSeeked = () => {
        videoDebug.event('seeked', { currentTime: video.currentTime });
        videoDebug.buffer(video.buffered, video.duration);
      };

      const handleWaiting = () => {
        videoDebug.warn('WAITING - buffering...');
        videoDebug.buffer(video.buffered, video.duration);
      };

      const handleStalled = () => {
        videoDebug.warn('STALLED - network issue');
        videoDebug.buffer(video.buffered, video.duration);
      };

      video.addEventListener('loadedmetadata', handleLoadedMetadata);
      video.addEventListener('canplay', handleCanPlayDebug);
      video.addEventListener('seeking', handleSeeking);
      video.addEventListener('seeked', handleSeeked);
      video.addEventListener('waiting', handleWaiting);
      video.addEventListener('stalled', handleStalled);

      return () => {
        video.removeEventListener('loadedmetadata', handleLoadedMetadata);
        video.removeEventListener('canplay', handleCanPlayDebug);
        video.removeEventListener('seeking', handleSeeking);
        video.removeEventListener('seeked', handleSeeked);
        video.removeEventListener('waiting', handleWaiting);
        video.removeEventListener('stalled', handleStalled);
      };
    }, [savedSettings.volume]);

    // Persist volume when user changes it via native controls
    useEffect(() => {
      const video = videoRef.current;
      if (!video) return;

      const handleVolumeChange = () => {
        updateVolume(video.volume);
      };

      video.addEventListener('volumechange', handleVolumeChange);
      return () => video.removeEventListener('volumechange', handleVolumeChange);
    }, [updateVolume]);

    const handleContextMenu = (e: React.MouseEvent) => {
      if (disableContextMenu) {
        e.preventDefault();
      }
    };

    const handleError = (e: React.SyntheticEvent<HTMLVideoElement>) => {
      const video = e.currentTarget;
      const errorMsg = video.error?.message || 'Video playback error';
      videoDebug.error('Video error', { code: video.error?.code, message: errorMsg });
      setIsLoading(false);
      onError?.(errorMsg);
    };

    const handleTimeUpdate = () => {
      const video = videoRef.current;
      if (video && onTimeUpdate) {
        onTimeUpdate(video.currentTime, video.duration);
      }
    };

    // Determine if we should use AspectRatio wrapper or fill mode
    const isFillMode = aspectRatio === 'fill';
    const computedAspectRatio = aspectRatio === 'auto' || aspectRatio === 'fill' ? undefined : aspectRatio;

    // Video content
    const videoContent = (
      <>
        {/* Preloader */}
        {showPreloader && isLoading && (
          <div
            className={cn(
              'absolute inset-0 flex items-center justify-center bg-muted/30 backdrop-blur-sm z-10'
            )}
          >
            <Preloader size="lg" spinnerClassName="text-white" />
          </div>
        )}

        {/* Video */}
        <video
          ref={videoRef}
          className={cn('w-full h-full object-cover', videoClassName)}
          src={videoUrl}
          autoPlay={autoPlay}
          muted={muted}
          loop={loop}
          playsInline={playsInline}
          preload={preload}
          controls={controls}
          poster={source.poster}
          onContextMenu={handleContextMenu}
          onLoadStart={onLoadStart}
          onCanPlay={onCanPlay}
          onPlay={onPlay}
          onPause={onPause}
          onPlaying={() => setIsLoading(false)}
          onEnded={onEnded}
          onError={handleError}
          onTimeUpdate={handleTimeUpdate}
        />
      </>
    );

    // Fill mode - no AspectRatio wrapper
    if (isFillMode) {
      return (
        <div className={cn('relative w-full h-full overflow-hidden', className)}>
          {videoContent}
        </div>
      );
    }

    // Normal mode with AspectRatio
    return (
      <div className={cn('relative overflow-hidden', className)}>
        <AspectRatio ratio={computedAspectRatio}>
          {videoContent}
        </AspectRatio>
      </div>
    );
  }
);

NativeProvider.displayName = 'NativeProvider';
