import React, { useEffect, useState, useRef, useCallback } from 'react';
import { View, Text, Modal, ActivityIndicator, Pressable } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import {
  RewardedAd,
  RewardedAdEventType,
  AdEventType,
  TestIds,
  RewardedAdReward,
  PaidEvent,
} from 'react-native-google-mobile-ads';

import { colors, typography, radius, shadow } from '@/constants/theme';
import { Button, ButtonText } from '@/components/ui/button';
import { grantBonusSession } from '@/lib/supabase';

/** Google's official rewarded test unit — always fills, independent of AdMob app review state. */
const AD_UNIT_ID = TestIds.REWARDED;

type AdAnalyticsEvent = 'ad_loaded' | 'ad_displayed' | 'ad_revenue';

/**
 * Single emit point for ad analytics.
 *
 * There is no analytics sink wired up in this project yet, so events go to the
 * console in a structured shape. Swap the body for the real transport (Supabase
 * insert, Segment, Firebase, …) and all three trackers below follow.
 */
function emitAdEvent(event: AdAnalyticsEvent, payload: Record<string, unknown>): void {
  console.log(`[AdMob][analytics] ${event}`, payload);
}

/*
 * The three trackers below each swallow their own errors. They are deliberately
 * total functions — they cannot throw — so no analytics failure can ever
 * interrupt the ad lifecycle or prevent grantBonusSession() from running.
 */

/** Fired on RewardedAdEventType.LOADED — the ad is filled and ready to present. */
export function trackAdLoaded(reward?: RewardedAdReward): void {
  try {
    emitAdEvent('ad_loaded', {
      adUnitId: AD_UNIT_ID,
      rewardType: reward?.type ?? null,
      rewardAmount: reward?.amount ?? null,
      at: new Date().toISOString(),
    });
  } catch (err) {
    console.warn('[AdMob] trackAdLoaded failed (non-blocking):', err);
  }
}

/** Fired on AdEventType.OPENED — the full-screen ad is on screen (the impression). */
export function trackAdDisplayed(): void {
  try {
    emitAdEvent('ad_displayed', {
      adUnitId: AD_UNIT_ID,
      at: new Date().toISOString(),
    });
  } catch (err) {
    console.warn('[AdMob] trackAdDisplayed failed (non-blocking):', err);
  }
}

/**
 * Fired on AdEventType.PAID — impression-level ad revenue reported by the SDK.
 *
 * `event` is optional because the package's own `AdEventPayload` mapping types
 * every non-error, non-rewarded event's payload as `undefined`. That mapping is
 * wrong for PAID: ios/RNGoogleMobileAds/RNGoogleMobileAdsFullScreenAd.mm sends
 * `{ value, precision, currency }` with the `paid` event for GADRewardedAd. We
 * read it defensively rather than cast, so a payload-less platform degrades to
 * nulls instead of throwing.
 */
export function trackAdRevenue(event?: PaidEvent): void {
  try {
    emitAdEvent('ad_revenue', {
      adUnitId: AD_UNIT_ID,
      value: event?.value ?? null,
      currency: event?.currency ?? null,
      precision: event?.precision ?? null,
      at: new Date().toISOString(),
    });
  } catch (err) {
    console.warn('[AdMob] trackAdRevenue failed (non-blocking):', err);
  }
}

interface RewardedAdModalProps {
  visible: boolean;
  onClose: () => void;
  onRewardEarned: () => void;
}

type AdStatus = 'idle' | 'loading' | 'loaded' | 'showing' | 'earned' | 'error';

/**
 * RewardedAdModal Component (US-7 Catvertising)
 *
 * Implements real rewarded video advertising via `react-native-google-mobile-ads`.
 * Uses Google's official `TestIds.REWARDED` ad unit for reliable test verification.
 * Grants exactly 1 bonus session upon receiving a genuine `RewardedAdEventType.EARNED_REWARD` callback.
 */
export function RewardedAdModal({ visible, onClose, onRewardEarned }: RewardedAdModalProps) {
  const [status, setStatus] = useState<AdStatus>('idle');
  const [errorMessage, setErrorMessage] = useState<string | null>(null);

  const adRef = useRef<RewardedAd | null>(null);
  const rewardEarnedRef = useRef<boolean>(false);
  const cleanupsRef = useRef<(() => void)[]>([]);

  const cleanupListeners = useCallback(() => {
    cleanupsRef.current.forEach((cleanup) => {
      try {
        cleanup();
      } catch (e) {
        // Ignore unsubscribe errors
      }
    });
    cleanupsRef.current = [];
    adRef.current = null;
  }, []);

  const loadAndShowAd = useCallback(() => {
    cleanupListeners();

    setStatus('loading');
    setErrorMessage(null);
    rewardEarnedRef.current = false;

    try {
      // 1. Instantiate RewardedAd using Google's official test ad unit
      const rewarded = RewardedAd.createForAdRequest(AD_UNIT_ID, {
        requestNonPersonalizedAdsOnly: true,
      });
      adRef.current = rewarded;

      // 2. Event listener: Ad Loaded -> Show full-screen video
      const unsubLoaded = rewarded.addAdEventListener(
        RewardedAdEventType.LOADED,
        (reward: RewardedAdReward) => {
          trackAdLoaded(reward);
          setStatus('loaded');
          rewarded
            .show()
            .then(() => {
              setStatus('showing');
            })
            .catch((err: Error) => {
              console.error('[AdMob] Error showing rewarded ad:', err);
              setStatus('error');
              setErrorMessage(err?.message || 'Failed to display sponsor video.');
            });
        }
      );

      // 3. Event listener: Reward Earned -> genuine SDK callback, grant bonus session
      const unsubEarned = rewarded.addAdEventListener(
        RewardedAdEventType.EARNED_REWARD,
        async (reward: RewardedAdReward) => {
          console.log('[AdMob] Earned reward:', reward);
          rewardEarnedRef.current = true;
          setStatus('earned');

          try {
            await grantBonusSession();
          } catch (err) {
            console.error('[AdMob] Failed to grant bonus session in Supabase:', err);
          }
        }
      );

      // 4. Event listener: Ad Opened -> the impression, i.e. the ad is on screen
      const unsubOpened = rewarded.addAdEventListener(AdEventType.OPENED, () => {
        trackAdDisplayed();
      });

      // 5. Event listener: Paid -> impression-level ad revenue from the SDK
      const unsubPaid = rewarded.addAdEventListener(
        AdEventType.PAID,
        (event: PaidEvent | undefined) => {
          trackAdRevenue(event);
        }
      );

      // 6. Event listener: Ad Closed -> Return to app flow
      const unsubClosed = rewarded.addAdEventListener(AdEventType.CLOSED, () => {
        console.log('[AdMob] Ad closed by user');
        cleanupListeners();
        if (rewardEarnedRef.current) {
          onRewardEarned();
        } else {
          onClose();
        }
      });

      // 7. Event listener: Error
      const unsubError = rewarded.addAdEventListener(AdEventType.ERROR, (error: Error) => {
        console.error('[AdMob] Rewarded ad error:', error);
        setStatus('error');
        setErrorMessage(error?.message || 'Unable to load sponsor video.');
      });

      cleanupsRef.current = [
        unsubLoaded,
        unsubEarned,
        unsubOpened,
        unsubPaid,
        unsubClosed,
        unsubError,
      ];

      // 8. Request ad load
      rewarded.load();
    } catch (err: any) {
      console.error('[AdMob] Failed to initialize RewardedAd:', err);
      setStatus('error');
      setErrorMessage(err?.message || 'AdMob initialization failed.');
    }
  }, [cleanupListeners, onClose, onRewardEarned]);

  useEffect(() => {
    if (visible) {
      loadAndShowAd();
    } else {
      cleanupListeners();
      setStatus('idle');
      setErrorMessage(null);
      rewardEarnedRef.current = false;
    }

    return () => {
      cleanupListeners();
    };
  }, [visible, loadAndShowAd, cleanupListeners]);

  if (!visible) return null;

  return (
    <Modal
      animationType="fade"
      transparent
      visible={visible}
      onRequestClose={() => {
        cleanupListeners();
        onClose();
      }}
    >
      <View
        style={{
          flex: 1,
          backgroundColor: 'rgba(29, 36, 43, 0.65)',
          justifyContent: 'center',
          alignItems: 'center',
          paddingHorizontal: 24,
        }}
      >
        <View
          style={[
            {
              backgroundColor: colors.surface,
              borderRadius: radius.lg,
              padding: 24,
              width: '100%',
              maxWidth: 380,
              alignItems: 'center',
              borderWidth: 1,
              borderColor: colors.border,
            },
            shadow.card,
          ]}
        >
          {status === 'error' ? (
            <>
              {/* Error State */}
              <View
                style={{
                  width: 56,
                  height: 56,
                  borderRadius: 28,
                  backgroundColor: '#FFF4E5',
                  alignItems: 'center',
                  justifyContent: 'center',
                  marginBottom: 16,
                }}
              >
                <Ionicons name="alert-circle-outline" size={32} color={colors.alert} />
              </View>

              <Text
                style={{
                  fontFamily: typography.h2.fontFamily,
                  fontSize: 18,
                  color: colors.textPrimary,
                  textAlign: 'center',
                  marginBottom: 8,
                }}
              >
                Sponsor Video Unavailable
              </Text>

              <Text
                style={{
                  fontFamily: typography.caption.fontFamily,
                  fontSize: 13,
                  lineHeight: 18,
                  color: colors.textSecondary,
                  textAlign: 'center',
                  marginBottom: 20,
                }}
              >
                {errorMessage || 'Unable to connect to the sponsor ad network right now. Please try again.'}
              </Text>

              <View className="w-full flex-row gap-3">
                <Button
                  size="default"
                  variant="outline"
                  onPress={() => {
                    cleanupListeners();
                    onClose();
                  }}
                  accessibilityRole="button"
                  accessibilityLabel="Cancel"
                  style={{
                    flex: 1,
                    borderRadius: radius.pill,
                    borderColor: colors.border,
                  }}
                >
                  <ButtonText
                    style={{
                      fontFamily: typography.bodyBold.fontFamily,
                      fontSize: 14,
                      color: colors.textSecondary,
                    }}
                  >
                    Cancel
                  </ButtonText>
                </Button>

                <Button
                  size="default"
                  onPress={loadAndShowAd}
                  accessibilityRole="button"
                  accessibilityLabel="Try loading ad again"
                  style={{
                    flex: 1,
                    borderRadius: radius.pill,
                    backgroundColor: colors.accent,
                  }}
                >
                  <ButtonText
                    style={{
                      fontFamily: typography.bodyBold.fontFamily,
                      fontSize: 14,
                      color: '#FFFFFF',
                    }}
                  >
                    Retry
                  </ButtonText>
                </Button>
              </View>
            </>
          ) : (
            <>
              {/* Loading / Presenting State */}
              <View
                style={{
                  width: 56,
                  height: 56,
                  borderRadius: 28,
                  backgroundColor: 'rgba(224, 122, 95, 0.12)',
                  alignItems: 'center',
                  justifyContent: 'center',
                  marginBottom: 16,
                }}
              >
                <ActivityIndicator size="small" color={colors.accent} />
              </View>

              <Text
                style={{
                  fontFamily: typography.h2.fontFamily,
                  fontSize: 18,
                  color: colors.textPrimary,
                  textAlign: 'center',
                  marginBottom: 8,
                }}
              >
                {status === 'showing' || status === 'earned'
                  ? 'Playing Sponsor Video...'
                  : 'Loading Sponsor Video...'}
              </Text>

              <Text
                style={{
                  fontFamily: typography.caption.fontFamily,
                  fontSize: 13,
                  lineHeight: 18,
                  color: colors.textSecondary,
                  textAlign: 'center',
                  marginBottom: 20,
                }}
              >
                Watch the complete message to unlock your 1 bonus practice scenario session.
              </Text>

              <Pressable
                onPress={() => {
                  cleanupListeners();
                  onClose();
                }}
                hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}
                accessibilityRole="button"
                accessibilityLabel="Cancel loading ad"
              >
                <Text
                  style={{
                    fontFamily: typography.caption.fontFamily,
                    fontSize: 13,
                    color: colors.textSecondary,
                    textDecorationLine: 'underline',
                  }}
                >
                  Cancel
                </Text>
              </Pressable>
            </>
          )}
        </View>
      </View>
    </Modal>
  );
}
