import React, { useCallback, useEffect, useState } from 'react';
import {
  View,
  Text,
  TouchableOpacity,
  Alert,
  AppState,
  Platform,
  Modal,
  ActivityIndicator,
} from 'react-native';
import { useFocusEffect, useNavigation } from '@react-navigation/native';
import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
import type { RootStackParamList } from '../../navigation';
import { useDispatch, useSelector } from 'react-redux';
import type { RootState, AppDispatch } from '../../store';
import {
  scanLocalModels,
  updateModelsDirectory,
  loadModelsDirectory,
  clearLocalError,
  setCurrentLoadedModel,
} from '../../store/modelsSlice';
import { loadModelConfigs } from '../../store/modelsThunks';
import { refreshHardwareInfo, refreshRamInfo } from '../../store/hardwareSlice';
import { loadModel, releaseModel } from '../../store/chatThunks';
import type { ModelConfig } from '../../store/types';
import ModelItem from './ModelItem';
import DirectoryPicker from './DirectoryPicker';
import DirectoryEditor from './DirectoryEditor';
import ModelsList from './ModelsList';
import { createStyles } from './styles';
import { useTheme } from '../../theme/ThemeProvider';
import {
  requestStoragePermission,
  checkStoragePermission,
} from '../../utils/permissions';

export default function LocalModelsScreen() {
  const { colors } = useTheme();
  const styles = createStyles(colors);
  const dispatch = useDispatch<AppDispatch>();
  const navigation = useNavigation<
    NativeStackNavigationProp<RootStackParamList>
  >();
  const {
    localModels,
    modelsDirectory,
    isLoadingLocal,
    localError,
    currentLoadedModel,
    downloadProgress,
  } = useSelector((state: RootState) =>
    state.models,
  );

  const ramFree = useSelector((s: RootState) => s.hardware.ramFree);
  const ramTotal = useSelector((s: RootState) => s.hardware.ramTotal);
  const isLoadingModel = useSelector((s: RootState) => s.models.isLoadingModel);
  const loadModelProgress = useSelector((s: RootState) => s.models.loadModelProgress ?? 0);
  const modelConfigs = useSelector((s: RootState) => s.models.modelConfigs ?? {});

  // Highlighted model path — tapping a card shows its footprint in the RAM bar
  const [highlightedPath, setHighlightedPath] = useState<string | null>(null);
  // Path du modèle en cours de chargement (pour spinner sur la bonne carte)
  const [loadingPath, setLoadingPath] = useState<string | null>(null);
  // Nom du modèle affiché dans la modal de chargement
  const [loadingModelName, setLoadingModelName] = useState<string | null>(null);

  const [editingDirectory, setEditingDirectory] = useState(false);
  const [tempDirectory, setTempDirectory] = useState(modelsDirectory);
  const [hasPermission, setHasPermission] = useState(false);

  useEffect(() => {
    checkStoragePermission().then(setHasPermission);

    const subscription = AppState.addEventListener('change', async (nextAppState) => {
      if (nextAppState === 'active') {
        const permitted = await checkStoragePermission();
        setHasPermission(permitted);
        if (permitted) {
          dispatch(scanLocalModels(modelsDirectory));
        }
      }
    });

    return () => {
      subscription.remove();
    };
  }, [dispatch, modelsDirectory]);

  useEffect(() => {
    // Load saved directory and scan on mount
    const initializeScreen = async () => {
      const result = await dispatch(loadModelsDirectory());
      if (result.payload) {
        const permitted = await checkStoragePermission();
        setHasPermission(permitted);
        if (permitted) {
          dispatch(scanLocalModels(result.payload as string));
        }
      }
      dispatch(loadModelConfigs());
    };

    initializeScreen();
    // Refresh RAM info on mount so the indicator is up to date
    dispatch(refreshHardwareInfo());
  }, [dispatch]);

  useEffect(() => {
    setTempDirectory(modelsDirectory);
  }, [modelsDirectory]);

  // Polling RAM toutes les secondes quand l'écran est actif
  useFocusEffect(
    useCallback(() => {  
      dispatch(refreshRamInfo());
      const interval = setInterval(() => {
        dispatch(refreshRamInfo());
      }, 1000);
      return () => clearInterval(interval);
    }, [dispatch]),
  );

  useEffect(() => {
    if (localError) {
      Alert.alert('Erreur', localError, [
        { text: 'OK', onPress: () => dispatch(clearLocalError()) },
      ]);
    }
  }, [localError, dispatch]);

  const handleRefresh = () => {
    dispatch(scanLocalModels(modelsDirectory));
  };

  const handleRequestPermission = async () => {
    await requestStoragePermission();
    // Attendre un peu puis revérifier
    setTimeout(async () => {
      const permitted = await checkStoragePermission();
      setHasPermission(permitted);
      if (permitted) {
        dispatch(scanLocalModels(modelsDirectory));
      }
    }, 1000);
  };

  

  const handleUpdateDirectory = () => {
    if (tempDirectory.trim()) {
      dispatch(updateModelsDirectory(tempDirectory.trim()));
      setEditingDirectory(false);
    }
  };

  const handleSelectCommonDirectory = (dir: string) => {
    setTempDirectory(dir);
    dispatch(updateModelsDirectory(dir));
    setEditingDirectory(false);
  };

  const handleLoadModel = async (modelPath: string, modelName: string) => {
    const cfg: ModelConfig = modelConfigs[modelPath] ?? {
      n_ctx: 2048,
      n_threads: 4,
      n_gpu_layers: 0,
      use_mlock: false,
      use_mmap: true,
    };
    setLoadingPath(modelPath);
    setLoadingModelName(modelName);
    try {
      dispatch(setCurrentLoadedModel(modelPath));
      const result = await dispatch(loadModel({ modelPath, cfg }));
      if (loadModel.rejected.match(result)) {
        dispatch(setCurrentLoadedModel(null));
        Alert.alert(
          'Erreur de chargement',
          String(result.payload ?? `Impossible de charger ${modelName}`),
        );
      }
    } finally {
      setLoadingPath(null);
      setLoadingModelName(null);
    }
  };

  const handleUnloadModel = async () => {
    await dispatch(releaseModel());
    dispatch(setCurrentLoadedModel(null));
    setHighlightedPath(null);
    dispatch(refreshRamInfo());
  };

  const renderModelItem = ({ item }: { item: typeof localModels[0] }) => {
    const isLoaded = currentLoadedModel === item.path;
    
    // Vérifier si ce modèle est en cours de téléchargement
    const downloadKey = Object.keys(downloadProgress).find(key => {
      const fileName = downloadProgress[key].modelId.split('/').pop();
      return item.name.includes(fileName || '');
    });
    
    const modelProgress = downloadKey ? downloadProgress[downloadKey] : null;
    const isDownloading = !!modelProgress;
    const progressPercent = modelProgress 
      ? (modelProgress.bytesWritten / modelProgress.contentLength) * 100 
      : 0;
    
    return (
      <ModelItem
        model={item}
        isLoaded={isLoaded}
        onPress={(path: string, name: string) => {
          setHighlightedPath(null);
          navigation.navigate('ModelConfig', { modelPath: path, modelName: name });
        }}
        onLoad={() => handleLoadModel(item.path, item.name)}
        onUnload={handleUnloadModel}
        isLoadingThisModel={isLoadingModel && loadingPath === item.path}
        onHighlight={() =>
          setHighlightedPath(prev => (prev === item.path ? null : item.path))
        }
        isHighlighted={highlightedPath === item.path}
        ramFree={ramFree}
        isDownloading={isDownloading}
        downloadProgress={progressPercent}
        bytesWritten={modelProgress?.bytesWritten || 0}
        contentLength={modelProgress?.contentLength || 0}
      />
    );
  };

  const fmtGB = (b: number) =>
    b >= 1073741824
      ? `${(b / 1073741824).toFixed(2)} GB`
      : b >= 1048576
      ? `${(b / 1048576).toFixed(0)} MB`
      : '—';

  // Highlighted model's size (null when nothing is selected)
  const highlightedModel = localModels.find(m => m.path === highlightedPath);
  const highlightedSize = highlightedModel?.size ?? null;

  // RAM bar proportions (flex values normalized to 0–100)
  const ramPct = ramTotal > 0 ? (ramFree / ramTotal) * 100 : -1;
  const ramColor = ramPct < 0
    ? colors.textTertiary
    : ramPct < 20
    ? colors.error
    : ramPct < 40
    ? colors.warning
    : colors.success;
  const usedFlex = ramTotal > 0 ? ((ramTotal - ramFree) / ramTotal) * 100 : 0;
  const modelExceedsRam = (highlightedSize ?? 0) > ramFree;
  const modelFlexRaw = highlightedSize && ramTotal > 0
    ? (Math.min(highlightedSize, ramFree) / ramTotal) * 100
    : 0;
  const freeFlex = Math.max(0, 100 - usedFlex - modelFlexRaw);
  const modelBarColor = modelExceedsRam ? colors.error : colors.warning;

  const progressStyle = { width: `${loadModelProgress}%` as `${number}%` };

  return (
    <View style={styles.container}>
      {/* Loading modal — même comportement que ModelConfigScreen */}
      <Modal visible={loadingModelName !== null} transparent animationType="fade">
        <View style={styles.loadingOverlay}>
          <View style={styles.loadingCard}>
            <Text style={styles.loadingTitle}>Chargement du modèle</Text>
            <Text style={styles.loadingSubtitle} numberOfLines={1}>
              {loadingModelName}
            </Text>
            <ActivityIndicator
              size="large"
              color={colors.primary}
              style={styles.activityIndicator}
            />
            <View style={styles.progressBarBg}>
              <View style={[styles.progressBarFill, progressStyle]} />
            </View>
            <Text style={styles.loadingPercent}>{loadModelProgress} %</Text>
          </View>
        </View>
      </Modal>

      {/* Directory Selection */}
      <View style={styles.directorySection}>
        <Text style={styles.sectionTitle}>Dossier des modèles</Text>
        {editingDirectory ? (
          <>
            <DirectoryEditor
              tempDirectory={tempDirectory}
              onChangeText={setTempDirectory}
              onCancel={() => {
                setTempDirectory(modelsDirectory);
                setEditingDirectory(false);
              }}
              onSave={handleUpdateDirectory}
              onSelectCommon={handleSelectCommonDirectory}
            />
            <DirectoryPicker
              currentDirectory={modelsDirectory}
              onSelectDirectory={handleSelectCommonDirectory}
            />
          </>
        ) : (
          <View style={styles.directoryDisplay}>
            <Text style={styles.directoryText} numberOfLines={2}>
              {modelsDirectory}
            </Text>
            <TouchableOpacity
              style={styles.changeButton}
              onPress={() => setEditingDirectory(true)}
            >
              <Text style={styles.changeButtonText}>Modifier</Text>
            </TouchableOpacity>
          </View>
        )}
        {/* RAM bar */}
        {Platform.OS === 'android' && ramTotal > 0 && (
          <View style={styles.ramSection}>
            {/* Header row */}
            <View style={styles.ramSectionHeader}>
              <Text style={styles.ramSectionLabel}>RAM</Text>
              <Text style={styles.ramHeaderRight}>
                Libre :{' '}
                <Text style={[{ color: ramColor }, styles.ramStrong]}>
                  {fmtGB(ramFree)} ({Math.round(ramPct)} %)
                </Text>
                {'  /  '}{fmtGB(ramTotal)}
              </Text>
            </View>

            {/* Progress bar */}
            <View style={styles.ramBarTrack}>
              {/* Used */}
              <View style={[styles.ramBarSeg, 
                { flex: usedFlex, backgroundColor: colors.textSecondary }
                ]} />
              {/* Model footprint */}
              {modelFlexRaw > 0 && (
                <View style={[styles.ramBarSeg, { 
                  flex: modelFlexRaw, 
                  backgroundColor: modelBarColor 
              }]} />
              )}
              {/* Remaining free */}
              {freeFlex > 0 && (
                <View style={[styles.ramBarSeg, { flex: freeFlex, backgroundColor: ramColor }]} />
              )}
            </View>

            {/* Legend when a model is highlighted */}
            {highlightedSize !== null && (
              <View style={styles.ramLegend}>
                <View style={styles.ramLegendRow}>
                  <View style={[styles.ramLegendDot, { backgroundColor: modelBarColor }]} />
                  <Text style={styles.ramLegendText}>
                    Modèle : {fmtGB(highlightedSize)}{' '}
                    <Text style={[{ color: modelBarColor }, styles.ramStrong]}>
                      ({Math.round((highlightedSize / ramTotal) * 100)} % de la RAM)
                    </Text>
                  </Text>
                </View>
                {modelExceedsRam && (
                  <Text style={styles.ramWarning}>
                  ⚠ Insuffisant — fermez d'autres apps ou choisissez une quantification plus légère
                  </Text>
                )}
              </View>
            )}

            {/* Hint when nothing selected */}
            {highlightedSize === null && (
              <Text style={styles.ramHint}>↑ Appuyez sur un modèle pour voir son impact</Text>
            )}
          </View>
        )}
      </View>

      {/* Models List */}
      <ModelsList
        models={localModels}
        isLoading={isLoadingLocal}
        onRefresh={handleRefresh}
        renderItem={renderModelItem}
      />
    </View>
  );
}
