import React, { useState, useEffect } from 'react'; import { View, Text, StyleSheet, ScrollView, SafeAreaView, StatusBar, TextInput, TouchableOpacity, Linking, Platform, Dimensions, Switch, } from 'react-native'; import CustomAlert from '../components/CustomAlert'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { useNavigation } from '@react-navigation/native'; import { MaterialIcons } from '@expo/vector-icons'; import { useTheme } from '../contexts/ThemeContext'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { useSettings } from '../hooks/useSettings'; import { SvgXml } from 'react-native-svg'; const { width } = Dimensions.get('window'); const isTablet = width >= 768; const AISettingsScreen: React.FC = () => { // CustomAlert state (must be inside the component) const [alertVisible, setAlertVisible] = useState(false); const [alertTitle, setAlertTitle] = useState(''); const [alertMessage, setAlertMessage] = useState(''); const [alertActions, setAlertActions] = useState void; style?: object }>>([ { label: 'OK', onPress: () => setAlertVisible(false) }, ]); const openAlert = ( title: string, message: string, actions?: Array<{ label: string; onPress?: () => void; style?: object }> ) => { setAlertTitle(title); setAlertMessage(message); if (actions && actions.length > 0) { setAlertActions( actions.map(a => ({ label: a.label, style: a.style, onPress: () => { a.onPress?.(); }, })) ); } else { setAlertActions([{ label: 'OK', onPress: () => setAlertVisible(false) }]); } setAlertVisible(true); }; const navigation = useNavigation(); const { currentTheme } = useTheme(); const insets = useSafeAreaInsets(); const { settings, updateSetting } = useSettings(); const OPENROUTER_SVG = ` OpenRouter `; const [apiKey, setApiKey] = useState(''); const [loading, setLoading] = useState(false); const [isKeySet, setIsKeySet] = useState(false); useEffect(() => { loadApiKey(); }, []); const loadApiKey = async () => { try { const savedKey = await AsyncStorage.getItem('openrouter_api_key'); if (savedKey) { setApiKey(savedKey); setIsKeySet(true); } } catch (error) { if (__DEV__) console.error('Error loading OpenRouter API key:', error); } }; const handleSaveApiKey = async () => { if (!apiKey.trim()) { openAlert('Error', 'Please enter a valid API key'); return; } if (!apiKey.startsWith('sk-or-')) { openAlert('Error', 'OpenRouter API keys should start with "sk-or-"'); return; } setLoading(true); try { await AsyncStorage.setItem('openrouter_api_key', apiKey.trim()); setIsKeySet(true); openAlert('Success', 'OpenRouter API key saved successfully!'); } catch (error) { openAlert('Error', 'Failed to save API key'); if (__DEV__) console.error('Error saving OpenRouter API key:', error); } finally { setLoading(false); } }; const handleRemoveApiKey = () => { openAlert( 'Remove API Key', 'Are you sure you want to remove your OpenRouter API key? This will disable AI chat features.', [ { label: 'Cancel', onPress: () => {} }, { label: 'Remove', onPress: async () => { try { await AsyncStorage.removeItem('openrouter_api_key'); setApiKey(''); setIsKeySet(false); openAlert('Success', 'API key removed successfully'); } catch (error) { openAlert('Error', 'Failed to remove API key'); } } } ] ); }; const handleGetApiKey = () => { Linking.openURL('https://openrouter.ai/keys'); }; return ( {/* Header */} navigation.goBack()} style={styles.backButton} > Settings {/* Empty for now, but ready for future actions */} AI Assistant {/* Info Card */} AI-Powered Chat Ask questions about any movie or TV show episode using advanced AI. Get insights about plot, characters, themes, trivia, and more - all powered by comprehensive TMDB data. Episode-specific context and analysis Plot explanations and character insights Behind-the-scenes trivia and facts Your own free OpenRouter API key {/* API Key Configuration */} OPENROUTER API KEY API Key Enter your OpenRouter API key to enable AI chat features {!isKeySet ? ( {loading ? 'Saving...' : 'Save API Key'} ) : ( Update Remove )} Get Free API Key from OpenRouter {/* Enable Toggle (top) */} Enable AI Chat updateSetting('aiChatEnabled', v)} trackColor={{ false: currentTheme.colors.elevation2, true: currentTheme.colors.primary }} thumbColor={settings.aiChatEnabled ? currentTheme.colors.white : currentTheme.colors.mediumEmphasis} ios_backgroundColor={currentTheme.colors.elevation2} /> When enabled, the Ask AI button will appear on content pages. {/* Status Card */} {isKeySet && ( AI Chat Enabled You can now ask questions about movies and TV shows. Look for the "Ask AI" button on content pages! )} {/* Usage Info */} How it works • OpenRouter provides access to multiple AI models{'\n'} • Your API key stays private and secure{'\n'} • Free tier includes generous usage limits{'\n'} • Chat with context about specific episodes/movies{'\n'} • Get detailed analysis and explanations {/* OpenRouter branding */} setAlertVisible(false)} actions={alertActions} /> ); }; const styles = StyleSheet.create({ container: { flex: 1, }, header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingHorizontal: 16, paddingTop: Platform.OS === 'android' ? (StatusBar.currentHeight || 0) + 8 : 8, }, backButton: { flexDirection: 'row', alignItems: 'center', padding: 8, }, backText: { fontSize: 17, marginLeft: 8, }, headerActions: { flexDirection: 'row', alignItems: 'center', }, headerButton: { padding: 8, marginLeft: 8, }, headerTitle: { fontSize: 34, fontWeight: 'bold', paddingHorizontal: 20, marginBottom: 24, }, scrollView: { flex: 1, }, scrollContent: { paddingBottom: 40, }, infoCard: { borderRadius: 16, padding: 20, marginHorizontal: 16, marginBottom: 20, }, infoHeader: { flexDirection: 'row', alignItems: 'center', marginBottom: 12, }, infoTitle: { fontSize: 20, fontWeight: '700', marginLeft: 12, }, infoDescription: { fontSize: 16, lineHeight: 24, marginBottom: 16, }, featureList: { gap: 8, }, featureItem: { flexDirection: 'row', alignItems: 'center', }, featureText: { fontSize: 15, marginLeft: 8, flex: 1, }, card: { borderRadius: 16, padding: 20, marginHorizontal: 16, marginBottom: 20, }, cardTitle: { fontSize: 13, fontWeight: '600', letterSpacing: 0.8, marginBottom: 16, }, apiKeySection: { gap: 12, }, label: { fontSize: 16, fontWeight: '600', }, description: { fontSize: 14, lineHeight: 20, }, input: { borderRadius: 12, padding: 16, fontSize: 16, fontFamily: Platform.OS === 'ios' ? 'Menlo' : 'monospace', borderWidth: 1, }, buttonContainer: { marginTop: 8, }, buttonRow: { flexDirection: 'row', gap: 12, }, saveButton: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', paddingVertical: 14, paddingHorizontal: 20, borderRadius: 12, }, saveButtonText: { color: 'white', fontSize: 16, fontWeight: '600', }, updateButton: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', paddingVertical: 14, paddingHorizontal: 20, borderRadius: 12, flex: 1, }, updateButtonText: { color: 'white', fontSize: 16, fontWeight: '600', }, removeButton: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', paddingVertical: 14, paddingHorizontal: 20, borderRadius: 12, borderWidth: 2, flex: 1, }, removeButtonText: { fontSize: 16, fontWeight: '600', }, getKeyButton: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', paddingVertical: 12, paddingHorizontal: 16, borderRadius: 12, marginTop: 8, }, getKeyButtonText: { fontSize: 15, fontWeight: '500', }, statusCard: { borderRadius: 16, padding: 20, marginBottom: 20, }, statusHeader: { flexDirection: 'row', alignItems: 'center', marginBottom: 8, }, statusTitle: { fontSize: 18, fontWeight: '600', marginLeft: 12, }, statusDescription: { fontSize: 15, lineHeight: 22, }, usageCard: { borderRadius: 16, padding: 20, }, usageTitle: { fontSize: 18, fontWeight: '600', marginBottom: 12, }, usageText: { fontSize: 15, lineHeight: 24, }, }); export default AISettingsScreen;