import React, { useCallback, useMemo, useRef, useState } from 'react';
import { View, ActivityIndicator, Platform, Alert, TouchableOpacity, Text } from 'react-native';
import { WebView, type WebViewMessageEvent } from 'react-native-webview';

import { PlaybasisProvider, usePlaybasis } from './PlaybasisProvider';
import { useTheme } from './theme/context';
import { getQwikBadgeAssetUrl } from './data/qwik-badge-assets';
import { getWidgetHtml } from './web/widgetHtml';
import type { WidgetBootstrapData, WidgetBridgeMessage } from './web/widgetTypes';

export interface QwikCardAppProps {
  apiKey: string;
  tenantId: string;
  playerId: string;
  baseUrl?: string;
  leaderboardId?: string;
  requestTimeoutMs?: number;
  requestRetries?: number;
}

function AppContent({ leaderboardId }: { leaderboardId?: string }) {
  const theme = useTheme();
  const { client, tenantId, playerId, baseUrl } = usePlaybasis();

  const webViewRef = useRef<WebView>(null);
  const [activeGame, setActiveGame] = useState<{ url: string; title?: string } | null>(null);
  const isQwikDark = theme.colors.background.toLowerCase() === '#0f1419';
  const gameHeaderStyle = {
    flexDirection: 'row' as const,
    alignItems: 'center' as const,
    paddingHorizontal: 16,
    paddingVertical: 12,
    borderBottomWidth: 1,
    borderBottomColor: isQwikDark ? '#e2e8f0' : theme.colors.surface,
    backgroundColor: isQwikDark ? '#ffffff' : theme.colors.background,
  };
  const gameHeaderTextColor = isQwikDark ? '#0f172a' : theme.colors.text.primary;
  const closeGame = () => {
    setActiveGame(null);
    webViewRef.current?.injectJavaScript(
      "window.PlaybasisWidget?.useWidgetStore?.getState?.()?.setActiveTab?.('play'); true;",
    );
  };

  const html = useMemo(() => getWidgetHtml(), []);

  const buildBootstrapPayload = useCallback(async (): Promise<WidgetBootstrapData> => {
    if (!playerId) {
      throw new Error('Missing playerId for widget bootstrap');
    }

    const [player, balances, playerQuests, questCatalog, allBadges, playerBadges, rewards] =
      await Promise.all([
        client.getPlayer(playerId),
        client.getBalances(playerId),
        client.getPlayerQuests(playerId),
        client.getQuests(),
        client.getBadges(),
        client.getPlayerBadges(playerId),
        client.getRewards().catch(() => []), // Gracefully handle if rewards endpoint doesn't exist
      ]);

    const xp = balances.find((b) => b.currency === 'xp')?.balance ?? 0;
    const qwikCoins = balances.find((b) => b.currency === 'qwik-coins')?.balance ?? 0;

    const leaderboardEntries = leaderboardId
      ? await (async () => {
          try {
            const res = await client.getLeaderboard(leaderboardId, { limit: 50 });
            const normalized = res.entries.map((entry) => ({
              userId: entry.playerId,
              rank: entry.rank,
              displayName: entry.displayName || 'Player',
              score: entry.score,
              isCurrentUser: entry.playerId === player.id,
            }));
            const hasCurrentUser = normalized.some((entry) => entry.isCurrentUser);

            if (!hasCurrentUser) {
              return [
                {
                  userId: player.id,
                  rank: 0,
                  displayName: player.displayName || 'You',
                  score: xp,
                  isCurrentUser: true,
                },
                ...normalized,
              ];
            }

            return normalized;
          } catch {
            return [
              {
                userId: player.id,
                rank: 0,
                displayName: player.displayName || 'You',
                score: xp,
                isCurrentUser: true,
              },
            ];
          }
        })()
      : [
          {
            userId: player.id,
            rank: 0,
            displayName: player.displayName || 'You',
            score: xp,
            isCurrentUser: true,
          },
        ];

    return {
      user: {
        userId: player.id,
        level: Math.max(1, Math.floor(xp / 1000) + 1),
        exp: xp,
        compositeScore: xp,
        positiveChangePct: 0,
      },
      wallet: {
        currency: 'XP',
        balance: xp,
        earnedDelta: 0,
        qwikCoins,
      },
      quests: (() => {
        const quests = playerQuests.length > 0 ? playerQuests : questCatalog;
        const nowIso = new Date().toISOString().slice(0, 10);
        return quests.map((q) => {
          const target = q.target ?? 1;
          const current = q.progress ?? 0;
          const progressPct = target > 0 ? Math.round((current / target) * 100) : 0;
          const status = q.status === 'completed' ? 'completed' : 'available';

          return {
            questId: q.id,
            title: q.name,
            description: q.description,
            type: 'mission',
            target,
            current,
            progressPct,
            startDate: nowIso,
            endDate: q.expiresAt,
            status,
            rewards: {
              xp: q.rewards?.find((r) => r.type === 'points')?.amount || 100,
              badges: (q.rewards
                ?.filter((r) => r.type === 'badge')
                .map((r) => r.badgeId)
                .filter(Boolean) || []) as string[],
            },
          };
        });
      })(),
      badges: allBadges.map((b) => ({
        id: b.id,
        name: b.name,
        rarity: 'common',
        unlocked: playerBadges.some((pb) => pb.id === b.id && pb.isEarned),
        imageUrl: b.imageUrl || (b.slug ? getQwikBadgeAssetUrl(b.slug) : undefined),
      })),
      rewards: rewards.map((r) => ({
        id: r.id,
        name: r.name,
        description: r.description || '',
        cost: r.cost || 0,
        imageUrl: r.imageUrl,
      })),
      activities: [],
      leaderboardEntries,
      tenantId,
    };
  }, [client, leaderboardId, playerId, tenantId]);

  const handleMessage = useCallback(
    async (event: WebViewMessageEvent) => {
      let message: WidgetBridgeMessage;
      try {
        message = JSON.parse(event.nativeEvent.data) as WidgetBridgeMessage;
      } catch {
        return;
      }

      if (message.type === 'ERROR') {
        // Handle errors from WebView
        console.error('[QwikCardApp] WebView Error:', message.error);
        Alert.alert('Widget Error', message.error || 'An unknown error occurred in the widget.');
        return;
      }

      if (message.type === 'OPEN_GAME') {
        setActiveGame({ url: message.url, title: message.title });
        return;
      }

      if (message.type !== 'REQUEST') return;

      const sendResponse = (payload: WidgetBridgeMessage) => {
        const js = `window.__PB_HANDLE_NATIVE_MESSAGE__ && window.__PB_HANDLE_NATIVE_MESSAGE__(${JSON.stringify(
          payload,
        )}); true;`;
        webViewRef.current?.injectJavaScript(js);
      };

      const requestId = message.requestId;

      if (!playerId) {
        sendResponse({
          type: 'RESPONSE',
          requestId,
          ok: false,
          error: 'PlayerId is required for widget data requests',
        });
        return;
      }

      try {
        switch (message.resource) {
          case 'bootstrap': {
            const data = await buildBootstrapPayload();
            sendResponse({ type: 'RESPONSE', requestId, ok: true, data });
            return;
          }
          default: {
            sendResponse({
              type: 'RESPONSE',
              requestId,
              ok: false,
              error: `Unsupported resource: ${String((message as any).resource)}`,
            });
            return;
          }
        }
      } catch (error) {
        sendResponse({
          type: 'RESPONSE',
          requestId,
          ok: false,
          error: error instanceof Error ? error.message : 'Failed to process widget request',
        });
      }
    },
    [buildBootstrapPayload, playerId],
  );

  const injectedJavaScript = useMemo(() => {
    // Seed initial config for the widget and establish a stable native->web message handler.
    // The web layer will immediately request `bootstrap` from native.
    const initPayload: WidgetBridgeMessage = {
      type: 'INIT',
      config: {
        tenantId,
        playerId: playerId ?? '',
        baseUrl,
      },
      platform: Platform.OS,
    };
    return `window.__PB_INIT__ = ${JSON.stringify(initPayload)}; true;`;
  }, [tenantId, playerId, baseUrl]);

  if (!playerId) {
    return (
      <View
        style={{
          flex: 1,
          alignItems: 'center',
          justifyContent: 'center',
          backgroundColor: theme.colors.background,
        }}
      >
        <ActivityIndicator size="large" color={theme.colors.primary} />
      </View>
    );
  }

  return (
    <View style={{ flex: 1, backgroundColor: theme.colors.background }}>
      <View style={{ flex: 1, display: activeGame ? 'none' : 'flex' }}>
        <WebView
          ref={webViewRef}
          originWhitelist={['*']}
          source={{ html }}
          onMessage={handleMessage}
          injectedJavaScript={injectedJavaScript}
          javaScriptEnabled
          domStorageEnabled
          allowsInlineMediaPlayback
          startInLoadingState
          renderLoading={() => (
            <View
              style={{
                flex: 1,
                alignItems: 'center',
                justifyContent: 'center',
                backgroundColor: theme.colors.background,
              }}
            >
              <ActivityIndicator size="large" color={theme.colors.primary} />
            </View>
          )}
          // Reduce common RN/WebView UX papercuts.
          keyboardDisplayRequiresUserAction={false as any}
          setSupportMultipleWindows={false}
          // Avoid white flashes on iOS.
          style={{ backgroundColor: theme.colors.background }}
        />
      </View>
      {activeGame && (
        <View style={{ flex: 1 }}>
          <View style={gameHeaderStyle}>
            <TouchableOpacity onPress={closeGame} style={{ paddingVertical: 4, paddingRight: 8 }}>
              <Text style={{ color: theme.colors.primary, fontWeight: '700' }}>← Arcade</Text>
            </TouchableOpacity>
            <Text
              style={{
                marginLeft: 4,
                color: gameHeaderTextColor,
                fontWeight: '700',
              }}
            >
              {activeGame.title || 'Play'}
            </Text>
          </View>
          <WebView
            originWhitelist={['*']}
            source={{ uri: activeGame.url }}
            javaScriptEnabled
            domStorageEnabled
            allowsInlineMediaPlayback
            startInLoadingState
          />
        </View>
      )}
    </View>
  );
}

export function QwikCardApp(props: QwikCardAppProps) {
  return (
    <PlaybasisProvider {...props}>
      <AppContent leaderboardId={props.leaderboardId} />
    </PlaybasisProvider>
  );
}
