/**
 * Hook for resolving presigned image URLs from the Media Service v2 stream endpoint.
 * 
 * The stream endpoint returns a 302 redirect to the presigned URL.
 * For images, this is always the presigned original file URL.
 * 
 * Usage:
 * ```jsx
 * const { imageUrl, loading, error, refresh } = usePresignedImage(fileId);
 * 
 * return <img src={imageUrl} alt="..." />;
 * ```
 * 
 * With options:
 * ```jsx
 * const { imageUrl } = usePresignedImage(fileId, {
 *   accountType: "instructor",
 *   enterpriseAccountId: affiliateId,
 *   fallbackUrl: "/placeholder.png",
 * });
 * ```
 */
import { useState, useEffect, useCallback, useRef } from "react";
import useMediaServiceV2 from "./useMediaServiceV2";

/**
 * @typedef {Object} UsePresignedImageOptions
 * @property {string} [accountType] - Account type override
 * @property {string} [enterpriseAccountId] - Enterprise ID for instructor affiliate
 * @property {string} [fallbackUrl] - Fallback URL if resolution fails
 * @property {boolean} [autoRefresh] - Auto-refresh URL before expiry (default: false)
 * @property {number} [refreshBuffer] - Seconds before expiry to refresh (default: 60)
 */

/**
 * @typedef {Object} UsePresignedImageResult
 * @property {string|null} imageUrl - Resolved presigned URL or fallback
 * @property {boolean} loading - Whether URL is being resolved
 * @property {Error|null} error - Error if resolution failed
 * @property {function(): Promise<string|null>} refresh - Manually refresh the URL
 * @property {function(): void} clear - Clear cached URL
 */

// Global cache for presigned URLs with expiry tracking
const urlCache = new Map();

/**
 * Parse expiry from presigned URL (S3/Spaces URLs contain X-Amz-Expires or Expires param).
 * @param {string} url - Presigned URL
 * @returns {number|null} Expiry timestamp in ms, or null if not found
 */
const parseUrlExpiry = (url) => {
  if (!url) return null;
  
  try {
    const urlObj = new URL(url);
    
    // Check for X-Amz-Date and X-Amz-Expires (AWS S3 style)
    const amzDate = urlObj.searchParams.get("X-Amz-Date");
    const amzExpires = urlObj.searchParams.get("X-Amz-Expires");
    
    if (amzDate && amzExpires) {
      // Parse ISO 8601 basic format: 20250101T120000Z
      const year = amzDate.slice(0, 4);
      const month = amzDate.slice(4, 6);
      const day = amzDate.slice(6, 8);
      const hour = amzDate.slice(9, 11);
      const min = amzDate.slice(11, 13);
      const sec = amzDate.slice(13, 15);
      const dateMs = Date.parse(`${year}-${month}-${day}T${hour}:${min}:${sec}Z`);
      return dateMs + parseInt(amzExpires, 10) * 1000;
    }
    
    // Check for Expires param (some providers)
    const expires = urlObj.searchParams.get("Expires");
    if (expires) {
      return parseInt(expires, 10) * 1000;
    }
    
    return null;
  } catch {
    return null;
  }
};

/**
 * Hook for resolving presigned image URLs from the Media Service v2.
 * 
 * @param {string|null} fileId - File ID to resolve
 * @param {UsePresignedImageOptions} [options] - Options
 * @returns {UsePresignedImageResult}
 */
const usePresignedImage = (fileId, options = {}) => {
  const {
    accountType,
    enterpriseAccountId,
    fallbackUrl = null,
    autoRefresh = false,
    refreshBuffer = 60,
  } = options;

  const media = useMediaServiceV2({
    accountType,
    enterpriseAccountId,
  });

  const [imageUrl, setImageUrl] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const refreshTimerRef = useRef(null);
  const mountedRef = useRef(true);

  /**
   * Clear any scheduled refresh timer.
   */
  const clearRefreshTimer = useCallback(() => {
    if (refreshTimerRef.current) {
      clearTimeout(refreshTimerRef.current);
      refreshTimerRef.current = null;
    }
  }, []);

  /**
   * Schedule auto-refresh before URL expiry.
   * @param {string} url - Presigned URL
   */
  const scheduleRefresh = useCallback(
    (url) => {
      if (!autoRefresh || !url) return;
      
      clearRefreshTimer();
      
      const expiry = parseUrlExpiry(url);
      if (!expiry) return;
      
      const now = Date.now();
      const refreshAt = expiry - refreshBuffer * 1000;
      const delay = refreshAt - now;
      
      if (delay > 0) {
        refreshTimerRef.current = setTimeout(() => {
          if (mountedRef.current) {
            refresh();
          }
        }, delay);
      }
    },
    [autoRefresh, refreshBuffer, clearRefreshTimer]
  );

  /**
   * Resolve presigned URL for the file.
   * @returns {Promise<string|null>}
   */
  const resolve = useCallback(async () => {
    if (!fileId) {
      setImageUrl(fallbackUrl);
      return fallbackUrl;
    }

    // Check cache first
    const cached = urlCache.get(fileId);
    if (cached) {
      const expiry = parseUrlExpiry(cached);
      // Use cached if not expired (with buffer)
      if (!expiry || expiry > Date.now() + refreshBuffer * 1000) {
        setImageUrl(cached);
        scheduleRefresh(cached);
        return cached;
      }
      // Clear expired cache
      urlCache.delete(fileId);
    }

    setLoading(true);
    setError(null);

    try {
      const presignedUrl = await media.resolvePresignedUrl(fileId);
      
      if (!mountedRef.current) return null;
      
      if (presignedUrl) {
        urlCache.set(fileId, presignedUrl);
        setImageUrl(presignedUrl);
        scheduleRefresh(presignedUrl);
        return presignedUrl;
      }
      
      setImageUrl(fallbackUrl);
      return fallbackUrl;
    } catch (err) {
      if (!mountedRef.current) return null;
      
      setError(err);
      setImageUrl(fallbackUrl);
      return fallbackUrl;
    } finally {
      if (mountedRef.current) {
        setLoading(false);
      }
    }
  }, [fileId, fallbackUrl, media, refreshBuffer, scheduleRefresh]);

  /**
   * Manually refresh the URL (clears cache).
   * @returns {Promise<string|null>}
   */
  const refresh = useCallback(async () => {
    if (fileId) {
      urlCache.delete(fileId);
    }
    return resolve();
  }, [fileId, resolve]);

  /**
   * Clear cached URL for this file.
   */
  const clear = useCallback(() => {
    if (fileId) {
      urlCache.delete(fileId);
    }
    setImageUrl(null);
    setError(null);
    clearRefreshTimer();
  }, [fileId, clearRefreshTimer]);

  // Resolve URL when fileId changes
  useEffect(() => {
    mountedRef.current = true;
    resolve();
    
    return () => {
      mountedRef.current = false;
      clearRefreshTimer();
    };
  }, [fileId, resolve, clearRefreshTimer]);

  return {
    imageUrl,
    loading,
    error,
    refresh,
    clear,
  };
};

/**
 * Clear all cached presigned URLs.
 * Useful when user logs out or switches accounts.
 */
export const clearPresignedImageCache = () => {
  urlCache.clear();
};

export default usePresignedImage;
