/**
 * Tira de fotos de un registro. Muestra las ya sincronizadas (tabla `media`)
 * y las locales en cola (`media_outbox`). Permite añadir nuevas desde cámara
 * o galería; antes de encolarlas les estampa un pie de página georreferenciado
 * (logo + proyecto + fecha + coordenadas) capturado con react-native-view-shot.
 *
 * El pie de página es configurable desde PhotoSettingsScreen (icono ⚙).
 */
import * as ImagePicker from 'expo-image-picker';
import * as Location from 'expo-location';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import {
  Alert,
  Image,
  ScrollView,
  StyleSheet,
  Text,
  TouchableOpacity,
  View,
} from 'react-native';
import { captureRef } from 'react-native-view-shot';
import { useNavigation } from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { Media, MediaParentEntity } from '../api/types';
import { absoluteUrl } from '../config';
import { enqueueMedia, getMediaOutboxFor, MediaOutboxRow } from '../db/outbox';
import { getActiveProjectId, getMediaFor, getProject } from '../db/repositories';
import { RootStackParamList } from '../navigation/types';
import {
  FooterConfig,
  loadFooterConfig,
  resolveFieldValue,
  StampMeta,
} from '../photo/footerConfig';
import { FooterOverlay } from '../photo/FooterOverlay';
import { COLORS } from './components';

// ─── tipos internos ────────────────────────────────────────────────────────

interface ComposingTask {
  uri: string;
  renderW: number;
  renderH: number;
  meta: StampMeta;
  config: FooterConfig;
}

type Nav = NativeStackNavigationProp<RootStackParamList>;

const MAX_STAMP_W = 2048;

// ─── helpers ───────────────────────────────────────────────────────────────

async function getCoords(): Promise<{ latitude: number; longitude: number } | null> {
  try {
    const { granted } = await Location.requestForegroundPermissionsAsync();
    if (!granted) return null;
    const loc = await Location.getCurrentPositionAsync({
      accuracy: Location.Accuracy.Balanced,
    });
    return loc.coords;
  } catch {
    return null;
  }
}

function formatCoords(lat: number, lng: number): string {
  const la = lat >= 0 ? 'N' : 'S';
  const lo = lng >= 0 ? 'E' : 'O';
  return `${Math.abs(lat).toFixed(5)}°${la}, ${Math.abs(lng).toFixed(5)}°${lo}`;
}

// ─── componente ────────────────────────────────────────────────────────────

export function MediaStrip({
  parentEntity,
  parentId,
  canUpload,
}: {
  parentEntity: MediaParentEntity;
  parentId: number;
  canUpload: boolean;
}) {
  const navigation = useNavigation<Nav>();
  const [synced, setSynced]   = useState<Media[]>([]);
  const [pending, setPending] = useState<MediaOutboxRow[]>([]);
  const [composing, setComposing] = useState<ComposingTask | null>(null);

  const captureViewRef = useRef<View>(null);
  const resolveRef = useRef<((uri: string) => void) | null>(null);
  const rejectRef  = useRef<((e: unknown) => void) | null>(null);

  // ── cargar datos ──────────────────────────────────────────────────────────

  const refresh = useCallback(async () => {
    const [s, p] = await Promise.all([
      getMediaFor(parentEntity, parentId),
      getMediaOutboxFor(parentEntity, parentId),
    ]);
    setSynced(s);
    setPending(p);
  }, [parentEntity, parentId]);

  useEffect(() => { void refresh(); }, [refresh]);

  // ── compositing (ViewShot) ────────────────────────────────────────────────

  /** Llamado por Image.onLoad cuando la imagen del composer ya está dibujada. */
  const onCaptureImageLoaded = useCallback(() => {
    // Un frame para que el layout nativo finalice antes de capturar.
    setTimeout(async () => {
      if (!captureViewRef.current) {
        rejectRef.current?.(new Error('captureRef is null'));
        setComposing(null);
        return;
      }
      try {
        const uri = await captureRef(captureViewRef, { format: 'jpg', quality: 0.85 });
        resolveRef.current?.(uri);
      } catch (e) {
        rejectRef.current?.(e);
      } finally {
        setComposing(null);
        resolveRef.current = null;
        rejectRef.current  = null;
      }
    }, 80);
  }, []);

  /**
   * Estampa el pie de página sobre `rawUri`.
   * Si el footer está desactivado o vacío devuelve el URI original intacto.
   */
  async function stamp(rawUri: string, origW: number, origH: number): Promise<string> {
    const [config, projectId] = await Promise.all([
      loadFooterConfig(),
      getActiveProjectId(),
    ]);

    const hasContent = config.enabled &&
      (config.logoUri != null || config.fields.some((f) => f.enabled));
    if (!hasContent) return rawUri;

    let projectName: string | null = null;
    if (projectId != null) {
      const proj = await getProject(projectId);
      projectName = proj?.name ?? null;
    }

    const coordsRaw = await getCoords();
    const meta: StampMeta = {
      projectName,
      date: new Date().toLocaleString('es-ES', {
        year: 'numeric', month: '2-digit', day: '2-digit',
        hour: '2-digit', minute: '2-digit',
      }),
      coordinates: coordsRaw ? formatCoords(coordsRaw.latitude, coordsRaw.longitude) : null,
    };

    const scale   = Math.min(1, MAX_STAMP_W / origW);
    const renderW = Math.round(origW * scale);
    const renderH = Math.round(origH * scale);

    return new Promise<string>((resolve, reject) => {
      resolveRef.current = resolve;
      rejectRef.current  = reject;
      setComposing({ uri: rawUri, renderW, renderH, meta, config });
    });
  }

  // ── captura de foto ───────────────────────────────────────────────────────

  const addPhoto = useCallback(
    async (source: 'camera' | 'library') => {
      const perm =
        source === 'camera'
          ? await ImagePicker.requestCameraPermissionsAsync()
          : await ImagePicker.requestMediaLibraryPermissionsAsync();
      if (!perm.granted) {
        Alert.alert('Permiso necesario', 'Concede el permiso para añadir fotos.');
        return;
      }

      const result =
        source === 'camera'
          ? await ImagePicker.launchCameraAsync({ quality: 0.85 })
          : await ImagePicker.launchImageLibraryAsync({ quality: 0.85, mediaTypes: 'images' });
      if (result.canceled || !result.assets?.length) return;

      const asset = result.assets[0];

      let finalUri: string;
      try {
        finalUri = await stamp(asset.uri, asset.width ?? 1920, asset.height ?? 1080);
      } catch {
        // Si el stamping falla, usar la foto original.
        finalUri = asset.uri;
      }

      await enqueueMedia({
        parentEntity,
        parentId,
        localUri: finalUri,
        fileName: asset.fileName ?? undefined,
        mimeType: asset.mimeType ?? 'image/jpeg',
        category: 'image',
      });
      await refresh();
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [parentEntity, parentId, refresh],
  );

  const onAdd = useCallback(() => {
    Alert.alert('Añadir foto', undefined, [
      { text: 'Cámara', onPress: () => void addPhoto('camera') },
      { text: 'Galería', onPress: () => void addPhoto('library') },
      { text: 'Cancelar', style: 'cancel' },
    ]);
  }, [addPhoto]);

  // ─── render ───────────────────────────────────────────────────────────────

  if (synced.length === 0 && pending.length === 0 && !canUpload) return null;

  return (
    <View style={styles.wrapper}>
      {/* Cabecera con icono de configuración */}
      {canUpload && (
        <View style={styles.header}>
          <Text style={styles.headerLabel}>Fotos</Text>
          <TouchableOpacity onPress={() => navigation.navigate('PhotoSettings')}>
            <Text style={styles.gear}>⚙</Text>
          </TouchableOpacity>
        </View>
      )}

      {/* Tira de miniaturas */}
      <ScrollView
        horizontal
        showsHorizontalScrollIndicator={false}
        contentContainerStyle={styles.row}
      >
        {canUpload && (
          <TouchableOpacity style={styles.addBtn} onPress={onAdd}>
            <Text style={styles.addPlus}>＋</Text>
            <Text style={styles.addText}>Foto</Text>
          </TouchableOpacity>
        )}
        {pending.map((m) => (
          <View key={m.uuid} style={styles.thumbWrap}>
            <Image source={{ uri: m.local_uri }} style={styles.thumb} />
            <View
              style={[
                styles.tag,
                { backgroundColor: m.status === 'error' ? COLORS.danger : COLORS.warn },
              ]}
            >
              <Text style={styles.tagText}>
                {m.status === 'error' ? 'error' : 'en cola'}
              </Text>
            </View>
          </View>
        ))}
        {synced.map((m) => (
          <View key={`s${m.id}`} style={styles.thumbWrap}>
            <Image source={{ uri: absoluteUrl(m.url) }} style={styles.thumb} />
          </View>
        ))}
      </ScrollView>

      {/* Vista fuera de pantalla para compositar el pie de página */}
      {composing ? (
        <View
          ref={captureViewRef}
          collapsable={false}
          style={{
            position: 'absolute',
            top: 0,
            left: -(composing.renderW + 100),
            width: composing.renderW,
            height: composing.renderH,
            overflow: 'hidden',
          }}
        >
          <Image
            source={{ uri: composing.uri }}
            style={StyleSheet.absoluteFill}
            resizeMode="stretch"
            onLoad={onCaptureImageLoaded}
          />
          <FooterOverlay
            config={composing.config}
            meta={composing.meta}
            imageWidth={composing.renderW}
          />
        </View>
      ) : null}
    </View>
  );
}

// ─── estilos ──────────────────────────────────────────────────────────────

const styles = StyleSheet.create({
  wrapper: { marginVertical: 8 },
  header: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    paddingHorizontal: 2,
    marginBottom: 6,
  },
  headerLabel: { fontSize: 13, fontWeight: '600', color: COLORS.muted },
  gear: { fontSize: 18, color: COLORS.muted, paddingHorizontal: 4 },
  row: { gap: 8, paddingRight: 8 },
  addBtn: {
    width: 72,
    height: 72,
    borderRadius: 8,
    borderWidth: 1,
    borderColor: COLORS.primary,
    borderStyle: 'dashed',
    justifyContent: 'center',
    alignItems: 'center',
  },
  addPlus: { color: COLORS.primary, fontSize: 22, fontWeight: '700' },
  addText: { color: COLORS.primary, fontSize: 11 },
  thumbWrap: {
    width: 72,
    height: 72,
    borderRadius: 8,
    overflow: 'hidden',
    backgroundColor: COLORS.bg,
  },
  thumb: { width: '100%', height: '100%' },
  tag: {
    position: 'absolute',
    bottom: 0,
    left: 0,
    right: 0,
    paddingVertical: 1,
    alignItems: 'center',
  },
  tagText: { color: '#fff', fontSize: 9, fontWeight: '700' },
});
