/**
 * BigCrunchBannerView - React Native component for displaying banner ads
 */

import React, { useEffect, useRef, useCallback, useMemo } from 'react';
import {
  requireNativeComponent,
  ViewStyle,
  StyleSheet,
} from 'react-native';
import { BigCrunchAdsEventEmitter, NativeEventNames } from './NativeBigCrunchAds';
import type {
  BigCrunchBannerViewProps,
  BannerSize,
  AdError,
  AdRevenue,
  EventSubscription,
} from './types';

// Native component name
const NATIVE_COMPONENT_NAME = 'BigCrunchBannerView';

// Banner size dimensions
const BANNER_SIZES = {
  BANNER: { width: 320, height: 50 },
  LARGE_BANNER: { width: 320, height: 100 },
  MEDIUM_RECTANGLE: { width: 300, height: 250 },
  FULL_BANNER: { width: 468, height: 60 },
  LEADERBOARD: { width: 728, height: 90 },
  ADAPTIVE: { width: -1, height: -1 }, // Calculated dynamically
  SMART: { width: -1, height: -1 }, // Deprecated, use ADAPTIVE
};

// Native view component
const NativeBannerView = requireNativeComponent<any>(NATIVE_COMPONENT_NAME);

/**
 * React component for displaying BigCrunch banner ads
 *
 * @example
 * ```tsx
 * <BigCrunchBannerView
 *   placementId="banner-home"
 *   size="BANNER"
 *   onAdLoaded={() => console.log('Ad loaded')}
 *   onAdFailedToLoad={(error) => console.error('Ad failed to load', error)}
 * />
 * ```
 */
export const BigCrunchBannerView: React.FC<BigCrunchBannerViewProps> = ({
  placementId,
  size,
  autoLoad = true,
  refreshInterval = 0,
  customTargeting,
  style,
  onAdLoaded,
  onAdFailedToLoad,
  onAdImpression,
  onAdClicked,
  onAdOpened,
  onAdClosed,
  onAdRevenue,
}) => {
  const viewRef = useRef<any>(null);
  const subscriptionsRef = useRef<EventSubscription[]>([]);
  const viewIdRef = useRef<string>(`banner_${placementId}_${Date.now()}`);

  // Calculate banner size for layout
  // When size is undefined, config drives the ad size natively — use adaptive layout
  const bannerSize = useMemo(() => {
    if (size === undefined) {
      // No explicit size — let backend config drive the ad size
      // Use adaptive layout since config may specify smart/adaptive sizes
      return { width: 0, height: 0, adaptive: true, configDriven: true };
    }
    if (typeof size === 'object' && 'width' in size && 'height' in size) {
      // Custom size
      return size;
    } else if (typeof size === 'string' && size in BANNER_SIZES) {
      // Predefined size
      const dimensions = BANNER_SIZES[size as BannerSize];
      if (dimensions.width === -1 || dimensions.height === -1) {
        // Adaptive/Smart banner - will be calculated natively
        return { width: 0, height: 0, adaptive: true };
      }
      return dimensions;
    }
    // Unknown size string — fallback to adaptive layout
    return { width: 0, height: 0, adaptive: true };
  }, [size]);

  // Handle native events
  const handleNativeEvent = useCallback((_eventName: string, handler?: Function) => {
    return (event: any) => {
      // Match exclusively on viewId — two banner views sharing a placementId must
      // not receive each other's events. Native attaches viewId to every banner event.
      if (event.viewId === viewIdRef.current) {
        handler?.(event);
      }
    };
  }, []);

  // Setup event listeners
  useEffect(() => {
    const subscriptions: EventSubscription[] = [];

    if (onAdLoaded) {
      subscriptions.push(
        BigCrunchAdsEventEmitter.addListener(
          NativeEventNames.BANNER_AD_LOADED,
          handleNativeEvent(NativeEventNames.BANNER_AD_LOADED, onAdLoaded)
        )
      );
    }

    if (onAdFailedToLoad) {
      subscriptions.push(
        BigCrunchAdsEventEmitter.addListener(
          NativeEventNames.BANNER_AD_FAILED_TO_LOAD,
          handleNativeEvent(NativeEventNames.BANNER_AD_FAILED_TO_LOAD, (event: any) => {
            const error: AdError = {
              code: event.errorCode || 'UNKNOWN',
              message: event.errorMessage || 'Ad failed to load',
              underlyingError: event.underlyingError,
            };
            onAdFailedToLoad(error);
          })
        )
      );
    }

    if (onAdImpression) {
      subscriptions.push(
        BigCrunchAdsEventEmitter.addListener(
          NativeEventNames.BANNER_AD_IMPRESSION,
          handleNativeEvent(NativeEventNames.BANNER_AD_IMPRESSION, onAdImpression)
        )
      );
    }

    if (onAdClicked) {
      subscriptions.push(
        BigCrunchAdsEventEmitter.addListener(
          NativeEventNames.BANNER_AD_CLICKED,
          handleNativeEvent(NativeEventNames.BANNER_AD_CLICKED, onAdClicked)
        )
      );
    }

    if (onAdOpened) {
      subscriptions.push(
        BigCrunchAdsEventEmitter.addListener(
          NativeEventNames.BANNER_AD_OPENED,
          handleNativeEvent(NativeEventNames.BANNER_AD_OPENED, onAdOpened)
        )
      );
    }

    if (onAdClosed) {
      subscriptions.push(
        BigCrunchAdsEventEmitter.addListener(
          NativeEventNames.BANNER_AD_CLOSED,
          handleNativeEvent(NativeEventNames.BANNER_AD_CLOSED, onAdClosed)
        )
      );
    }

    if (onAdRevenue) {
      subscriptions.push(
        BigCrunchAdsEventEmitter.addListener(
          NativeEventNames.BANNER_AD_REVENUE,
          handleNativeEvent(NativeEventNames.BANNER_AD_REVENUE, (event: any) => {
            const revenue: AdRevenue = {
              valueMicros: event.valueMicros,
              currencyCode: event.currencyCode,
              adUnitId: event.adUnitId,
              precision: event.precision,
            };
            onAdRevenue(revenue);
          })
        )
      );
    }

    subscriptionsRef.current = subscriptions;

    // Cleanup on unmount
    return () => {
      subscriptions.forEach(sub => sub.remove());
      subscriptionsRef.current = [];
    };
  }, [
    placementId,
    handleNativeEvent,
    onAdLoaded,
    onAdFailedToLoad,
    onAdImpression,
    onAdClicked,
    onAdOpened,
    onAdClosed,
    onAdRevenue,
  ]);

  // Note: auto-loading is handled natively via the `autoLoad` prop (both view
  // managers trigger the load once placementId is set). Dispatching a loadAd
  // command here as well caused every banner to load twice.

  // Container styles
  const containerStyle: ViewStyle = useMemo(() => {
    const baseStyle: ViewStyle = {
      width: bannerSize.width > 0 ? bannerSize.width : 320,
      height: bannerSize.height > 0 ? bannerSize.height : 50,
      // Remove overflow: 'hidden' to avoid clipping the ad content
    };

    if ((bannerSize as any).adaptive) {
      // Adaptive banner - let it size itself
      baseStyle.alignSelf = 'stretch';
      baseStyle.width = '100%';
    }

    return StyleSheet.flatten([baseStyle, style]);
  }, [bannerSize, style]);

  // Native view props
  // Only send size/customWidth/customHeight when explicitly specified by the developer.
  // When omitted, the native SDK uses placement config sizes (e.g., smart/adaptive from backend).
  const nativeProps: any = {
    ref: viewRef,
    style: containerStyle,
    placementId,
    autoLoad,
    refreshInterval,
    customTargeting,
    viewId: viewIdRef.current,
  };

  // Only send size to native when explicitly set by the developer
  if (size !== undefined) {
    if (typeof size === 'string') {
      nativeProps.size = size;
    } else if (typeof size === 'object' && 'width' in size && 'height' in size) {
      nativeProps.size = 'CUSTOM';
      nativeProps.customWidth = size.width;
      nativeProps.customHeight = size.height;
    }
  }

  // Return the native view directly with the container style
  return <NativeBannerView {...nativeProps} />;
};

// Export as default
export default BigCrunchBannerView;