import React, { MouseEvent, useCallback, useEffect, useState } from 'react';
import { Box, Spinner, Text, as } from 'folds';
import { Icon, Icons } from '../icons';
import * as css from './YouTubeEmbed.css';
import { getYouTubeStream, isYouTubeStreamingAvailable, openExternalUrl } from '../../utils/tauri';

/**
 * Regex patterns to match YouTube URLs and extract video IDs
 */
const YOUTUBE_URL_PATTERNS = [
  // Standard youtube.com/watch?v=VIDEO_ID
  /(?:https?:\/\/)?(?:www\.)?youtube\.com\/watch\?(?:.*&)?v=([a-zA-Z0-9_-]{11})(?:&|$)/,
  // Short youtu.be/VIDEO_ID
  /(?:https?:\/\/)?(?:www\.)?youtu\.be\/([a-zA-Z0-9_-]{11})(?:\?|$|\/)?/,
  // Embedded youtube.com/embed/VIDEO_ID
  /(?:https?:\/\/)?(?:www\.)?youtube\.com\/embed\/([a-zA-Z0-9_-]{11})(?:\?|$)/,
  // Shorts youtube.com/shorts/VIDEO_ID
  /(?:https?:\/\/)?(?:www\.)?youtube\.com\/shorts\/([a-zA-Z0-9_-]{11})(?:\?|$)/,
  // YouTube Music music.youtube.com/watch?v=VIDEO_ID
  /(?:https?:\/\/)?music\.youtube\.com\/watch\?(?:.*&)?v=([a-zA-Z0-9_-]{11})(?:&|$)/,
];

/**
 * YouTube embed URL base - fallback when yt-dlp is not available
 * Using youtube-nocookie.com to avoid Error 153 and embedding restrictions
 */
const YOUTUBE_EMBED_BASE = 'https://www.youtube-nocookie.com/embed';

/**
 * YouTube oEmbed API base - used to fetch video metadata
 */
const YOUTUBE_OEMBED_API = 'https://www.youtube.com/oembed';

/**
 * Get YouTube thumbnail URL for a video
 * @param videoId The YouTube video ID
 * @returns The thumbnail URL (high quality)
 */
function getYouTubeThumbnailUrl(videoId: string): string {
  return `https://img.youtube.com/vi/${videoId}/hqdefault.jpg`;
}

/**
 * Fetch YouTube video title using oEmbed API
 * @param url The YouTube video URL
 * @returns The video title or null if fetch fails
 */
async function fetchYouTubeTitle(url: string): Promise<string | null> {
  try {
    const oembedUrl = `${YOUTUBE_OEMBED_API}?url=${encodeURIComponent(url)}&format=json`;
    const response = await fetch(oembedUrl);
    if (!response.ok) return null;
    const data = await response.json();
    return data.title || null;
  } catch {
    return null;
  }
}

/**
 * Checks if a URL is a YouTube URL
 * @param url The URL to check
 * @returns True if the URL is a YouTube URL
 */
export function isYouTubeUrl(url: string): boolean {
  return YOUTUBE_URL_PATTERNS.some((pattern) => pattern.test(url));
}

/**
 * Extracts the video ID from a YouTube URL
 * @param url The YouTube URL
 * @returns The video ID or null if not found
 */
export function extractYouTubeVideoId(url: string): string | null {
  let videoId: string | null = null;
  YOUTUBE_URL_PATTERNS.some((pattern) => {
    const match = url.match(pattern);
    if (match) {
      const [, id] = match;
      if (id) {
        videoId = id;
        return true;
      }
    }
    return false;
  });
  return videoId;
}

/**
 * Generates a YouTube embed URL for a video (fallback)
 * @param videoId The YouTube video ID
 * @returns The embed URL with parameters to avoid Error 153
 */
export function getYouTubeEmbedUrl(videoId: string): string {
  // Use youtube-nocookie.com and add parameters to help with embedding
  // autoplay=1 - start playing when loaded
  // rel=0 - only show related videos from same channel
  // modestbranding=1 - minimize YouTube branding
  // enablejsapi=1 - enable JavaScript API for better compatibility
  return `${YOUTUBE_EMBED_BASE}/${videoId}?autoplay=1&rel=0&modestbranding=1&enablejsapi=1`;
}

/**
 * Click handler for external links - uses Tauri shell on desktop/mobile
 */
const handleExternalLinkClick = (e: MouseEvent<HTMLAnchorElement>) => {
  const { href } = e.currentTarget;
  if (href && (href.startsWith('http://') || href.startsWith('https://'))) {
    e.preventDefault();
    openExternalUrl(href);
  }
};

type PlayerState = 
  | { status: 'thumbnail' }
  | { status: 'loading' }
  | { status: 'playing'; videoUrl: string; title: string }
  | { status: 'fallback-iframe' };

type YouTubeEmbedProps = {
  /** The original YouTube URL */
  url: string;
};

/**
 * YouTube embed component that shows thumbnail preview and uses yt-dlp
 * for direct ad-free streaming when clicked
 */
export const YouTubeEmbed = as<'div', YouTubeEmbedProps>(({ url, ...props }, ref) => {
  const videoId = extractYouTubeVideoId(url);
  const [playerState, setPlayerState] = useState<PlayerState>({ status: 'thumbnail' });
  const [videoTitle, setVideoTitle] = useState<string | null>(null);

  // Fetch video title on mount
  useEffect(() => {
    let cancelled = false;
    
    fetchYouTubeTitle(url).then((title) => {
      if (!cancelled) {
        setVideoTitle(title);
      }
    });

    return () => {
      cancelled = true;
    };
  }, [url]);

  const handlePlay = useCallback(async () => {
    if (!isYouTubeStreamingAvailable()) {
      setPlayerState({ status: 'fallback-iframe' });
      return;
    }

    setPlayerState({ status: 'loading' });

    try {
      const info = await getYouTubeStream(url);
      setPlayerState({ status: 'playing', videoUrl: info.video_url, title: info.title });
    } catch {
      setPlayerState({ status: 'fallback-iframe' });
    }
  }, [url]);

  if (!videoId) {
    return null;
  }

  const thumbnailUrl = getYouTubeThumbnailUrl(videoId);

  const renderHeader = (label: string) => (
    <div className={css.YouTubeEmbedHeader}>
      <Text
        as="a"
        href={url}
        target="_blank"
        rel="noopener noreferrer"
        size="T200"
        className={css.YouTubeEmbedLink}
        onClick={handleExternalLinkClick}
        truncate
      >
        {label}
      </Text>
    </div>
  );

  // Determine what to show in the header based on video title availability
  const getHeaderLabel = (suffix?: string) => {
    if (videoTitle) {
      return suffix ? `${videoTitle} ${suffix}` : videoTitle;
    }
    return suffix ? `YouTube ${suffix}` : 'YouTube';
  };

  // Thumbnail preview - click to play
  if (playerState.status === 'thumbnail') {
    return (
      <Box shrink="No" className={css.YouTubeEmbed} direction="Column" {...props} ref={ref}>
        {renderHeader(getHeaderLabel())}
        <button 
          type="button"
          className={css.YouTubeThumbnailButton}
          onClick={handlePlay}
          aria-label="Play video"
        >
          <img 
            src={thumbnailUrl} 
            alt="Video thumbnail" 
            className={css.YouTubeThumbnail}
          />
          <div className={css.YouTubePlayButton}>
            <Icon size="600" src={Icons.Play} />
          </div>
        </button>
      </Box>
    );
  }

  // Loading state
  if (playerState.status === 'loading') {
    return (
      <Box shrink="No" className={css.YouTubeEmbed} direction="Column" {...props} ref={ref}>
        {renderHeader(getHeaderLabel('- Loading...'))}
        <Box 
          className={css.YouTubeEmbedIframe} 
          alignItems="Center" 
          justifyContent="Center"
          style={{ background: '#000', display: 'flex' }}
        >
          <Spinner variant="Secondary" size="600" />
        </Box>
      </Box>
    );
  }

  // Direct stream via yt-dlp (ad-free)
  if (playerState.status === 'playing') {
    return (
      <Box shrink="No" className={css.YouTubeEmbed} direction="Column" {...props} ref={ref}>
        {renderHeader(`${playerState.title} (ad-free)`)}
        <video
          className={css.YouTubeEmbedIframe}
          src={playerState.videoUrl}
          controls
          autoPlay
          preload="metadata"
        >
          <track kind="captions" />
        </video>
      </Box>
    );
  }

  // Fallback to YouTube iframe
  const embedUrl = getYouTubeEmbedUrl(videoId);
  return (
    <Box shrink="No" className={css.YouTubeEmbed} direction="Column" {...props} ref={ref}>
      {renderHeader(getHeaderLabel())}
      <iframe
        className={css.YouTubeEmbedIframe}
        src={embedUrl}
        title="YouTube video player"
        allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
        allowFullScreen
        referrerPolicy="strict-origin-when-cross-origin"
      />
    </Box>
  );
});
