import { ReactNode, useCallback, useEffect } from 'react';
import { IThumbnailContent } from '../../../../types/matrix/common';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
import { decryptFile, downloadEncryptedMedia, isAuthenticatedMediaUrl, mxcUrlToHttp } from '../../../utils/matrix';
import { useMediaAuthentication } from '../../../hooks/useMediaAuthentication';
import { FALLBACK_MIMETYPE } from '../../../utils/mimeTypes';
import { getCurrentAccessToken } from '../../../utils/auth';

/**
 * Fetches media with authentication headers and returns a blob URL.
 * Falls back to unauthenticated request if authenticated request fails with 401.
 * If all attempts fail, returns the original URL to let the browser try directly.
 */
const fetchAuthenticatedMedia = async (
  url: string,
  accessToken: string | null
): Promise<string> => {
  try {
    let response = await fetch(url, {
      method: 'GET',
      headers: accessToken ? { Authorization: `Bearer ${accessToken}` } : undefined,
    });
    
    // If we got a 401 and we tried with auth, fallback to unauthenticated request
    if (!response.ok && response.status === 401 && accessToken) {
      console.warn('[ThumbnailContent] Auth failed (401), attempting unauthenticated fallback for:', url);
      response = await fetch(url, { method: 'GET' });
    }
    
    if (!response.ok) {
      console.warn(`[ThumbnailContent] Failed to fetch authenticated media (${response.status}), falling back to original URL`);
      return url;
    }
    const blob = await response.blob();
    return URL.createObjectURL(blob);
  } catch (error) {
    console.warn('[ThumbnailContent] Error fetching authenticated media, falling back to original URL:', error);
    return url;
  }
};

export type ThumbnailContentProps = {
  info: IThumbnailContent;
  renderImage: (src: string) => ReactNode;
};
export function ThumbnailContent({ info, renderImage }: ThumbnailContentProps) {
  const mx = useMatrixClient();
  const useAuthentication = useMediaAuthentication();

  // Check if we have valid thumbnail data
  const thumbInfo = info.thumbnail_info;
  const thumbMxcUrl = info.thumbnail_file?.url ?? info.thumbnail_url;
  const hasValidThumbnail = typeof thumbMxcUrl === 'string' && typeof thumbInfo?.mimetype === 'string';

  const [thumbSrcState, loadThumbSrc] = useAsyncCallback(
    useCallback(async () => {
      const encInfo = info.thumbnail_file;

      const mediaUrl = mxcUrlToHttp(mx, thumbMxcUrl, useAuthentication) ?? thumbMxcUrl;
      // Always use current session's token to avoid stale tokens during account switches
      const accessToken = getCurrentAccessToken();
      if (encInfo) {
        const fileContent = await downloadEncryptedMedia(
          mediaUrl,
          (encBuf) => decryptFile(encBuf, thumbInfo.mimetype ?? FALLBACK_MIMETYPE, encInfo),
          accessToken
        );
        return URL.createObjectURL(fileContent);
      }

      // For authenticated media, fetch with auth header and return blob URL
      if (useAuthentication && isAuthenticatedMediaUrl(mediaUrl)) {
        return fetchAuthenticatedMedia(mediaUrl, accessToken);
      }

      return mediaUrl;
    }, [mx, thumbMxcUrl, thumbInfo, info.thumbnail_file, useAuthentication])
  );

  useEffect(() => {
    // Only attempt to load thumbnail if we have valid data
    if (hasValidThumbnail) {
      loadThumbSrc();
    }
  }, [hasValidThumbnail, loadThumbSrc]);

  return thumbSrcState.status === AsyncStatus.Success ? renderImage(thumbSrcState.data) : null;
}
