# Ejemplo de Uso del SDK Unificado

## Función Storage - Mismo Código, Diferentes Plataformas

### 📱 Uso desde App Expo/React Native

```javascript
import SDK from '@apps-sdk/expo';

// Inicializar SDK
await SDK.init();

// Guardar datos
await SDK.storage.storeData('user_preferences', {
  theme: 'dark',
  language: 'es',
  notifications: true
});

// Obtener datos
const preferences = await SDK.storage.getData('user_preferences');
console.log(preferences); // { theme: 'dark', language: 'es', notifications: true }

// Guardar imagen en galería (funcionalidad móvil)
await SDK.storage.handleDownloadImageToGallery('file://path/to/image.jpg');

// Comprimir imagen
const compressedUri = await SDK.storage.compressImage('file://image.jpg', 2); // 2MB max
```

### 🌐 Uso desde App Web/Next.js

```javascript
import SDK from '@apps-sdk/web';

// Inicializar SDK
await SDK.init();

// Guardar datos (MISMA API)
await SDK.storage.storeData('user_preferences', {
  theme: 'dark',
  language: 'es',
  notifications: true
});

// Obtener datos (MISMA API)
const preferences = await SDK.storage.getData('user_preferences');
console.log(preferences); // { theme: 'dark', language: 'es', notifications: true }

// Descargar imagen (adaptado para web)
await SDK.storage.handleDownloadImage('https://example.com/image.jpg', 'my-image');

// Comprimir imagen (usando Canvas API)
const compressedBlob = await SDK.storage.compressImage(file, 2); // 2MB max
```

## 🔧 Implementación Interna (Cómo Funciona)

### Core Compartido (`@apps-sdk/core`)

```javascript
// src/storage/StorageCore.js
export class StorageCore {
  constructor(adapter) {
    this.adapter = adapter; // Inyección de dependencia
  }

  async storeData(key, value) {
    const serialized = JSON.stringify(value);
    return await this.adapter.setItem(key, serialized);
  }

  async getData(key) {
    const serialized = await this.adapter.getItem(key);
    return serialized ? JSON.parse(serialized) : null;
  }

  async removeData(key) {
    return await this.adapter.removeItem(key);
  }

  // Funciones específicas que delegan al adaptador
  async compressImage(source, maxSizeMB) {
    return await this.adapter.compressImage(source, maxSizeMB);
  }

  async handleDownloadImage(source, filename) {
    return await this.adapter.downloadImage(source, filename);
  }
}
```

### Adaptador Expo (`@apps-sdk/expo`)

```javascript
// src/adapters/StorageAdapter.js
import AsyncStorage from '@react-native-async-storage/async-storage';
import * as MediaLibrary from 'expo-media-library';
import { ImageManipulator } from 'expo-image-manipulator';

export class ExpoStorageAdapter {
  // Implementación básica
  async setItem(key, value) {
    return await AsyncStorage.setItem(key, value);
  }

  async getItem(key) {
    return await AsyncStorage.getItem(key);
  }

  async removeItem(key) {
    return await AsyncStorage.removeItem(key);
  }

  // Funcionalidades específicas de móvil
  async compressImage(imageUri, maxSizeMB) {
    const qualities = [0.8, 0.6, 0.4, 0.2];
    for (const quality of qualities) {
      const compressed = await ImageManipulator.manipulateAsync(
        imageUri,
        [],
        { compress: quality, format: 'jpeg' }
      );
      
      const fileSize = await this.getFileSize(compressed.uri);
      if (fileSize < maxSizeMB) {
        return compressed.uri;
      }
    }
    return null;
  }

  async downloadImage(source, filename) {
    // Lógica específica para guardar en galería móvil
    const { status } = await MediaLibrary.requestPermissionsAsync();
    if (status === 'granted') {
      return await MediaLibrary.createAssetAsync(source);
    }
    throw new Error('Gallery permission denied');
  }
}
```

### Adaptador Web (`@apps-sdk/web`)

```javascript
// src/adapters/StorageAdapter.js
export class WebStorageAdapter {
  // Implementación básica
  async setItem(key, value) {
    localStorage.setItem(key, value);
  }

  async getItem(key) {
    return localStorage.getItem(key);
  }

  async removeItem(key) {
    localStorage.removeItem(key);
  }

  // Funcionalidades adaptadas para web
  async compressImage(file, maxSizeMB) {
    return new Promise((resolve) => {
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');
      const img = new Image();
      
      img.onload = () => {
        // Lógica de compresión usando Canvas API
        canvas.width = img.width;
        canvas.height = img.height;
        ctx.drawImage(img, 0, 0);
        
        const qualities = [0.8, 0.6, 0.4, 0.2];
        for (const quality of qualities) {
          canvas.toBlob((blob) => {
            if (blob.size / 1024 / 1024 < maxSizeMB) {
              resolve(blob);
            }
          }, 'image/jpeg', quality);
        }
      };
      
      img.src = URL.createObjectURL(file);
    });
  }

  async downloadImage(source, filename) {
    // Lógica específica para descargar en navegador
    const response = await fetch(source);
    const blob = await response.blob();
    
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = filename;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    window.URL.revokeObjectURL(url);
  }
}
```

### Inicialización por Plataforma

#### Expo Package (`@apps-sdk/expo/index.js`)
```javascript
import { StorageCore } from '@apps-sdk/core';
import { ExpoStorageAdapter } from './adapters/StorageAdapter';

const storageAdapter = new ExpoStorageAdapter();
const storage = new StorageCore(storageAdapter);

export default {
  storage,
  // ... otros módulos
};
```

#### Web Package (`@apps-sdk/web/index.js`)
```javascript
import { StorageCore } from '@apps-sdk/core';
import { WebStorageAdapter } from './adapters/StorageAdapter';

const storageAdapter = new WebStorageAdapter();
const storage = new StorageCore(storageAdapter);

export default {
  storage,
  // ... otros módulos
};
```

## 🎯 Ventajas de Esta Arquitectura

### Para el Desarrollador
- **API Idéntica** - Mismo código en ambas plataformas
- **IntelliSense** - Mismos tipos TypeScript
- **Documentación única** - Una sola referencia

### Para el Mantenimiento
- **Lógica centralizada** - Bugs se arreglan una vez
- **Testing unificado** - Tests del core sirven para ambas plataformas
- **Features sincronizadas** - Nuevas funcionalidades llegan a ambas plataformas

### Ejemplo de Migración

#### Antes (SDK actual)
```javascript
// Solo funciona en Expo
import SDK from 'apps-sdk';
await SDK.storage.storeData('key', 'value');
```

#### Después (SDK unificado)
```javascript
// Funciona en Expo
import SDK from '@apps-sdk/expo';
await SDK.storage.storeData('key', 'value');

// Funciona en Web (MISMA API)
import SDK from '@apps-sdk/web';
await SDK.storage.storeData('key', 'value');
```

## 📦 Instalación

```bash
# Para proyectos Expo
npm install @apps-sdk/expo

# Para proyectos Web/Next.js
npm install @apps-sdk/web

# Para proyectos que necesiten ambos (monorepo)
npm install @apps-sdk/core @apps-sdk/expo @apps-sdk/web
```

Esta arquitectura permite que el 90% del código de tu aplicación sea idéntico entre plataformas, mientras que las diferencias específicas se manejan transparentemente en los adaptadores.

## 📄 Módulo Legal - Obtener Textos Legales

### Uso Básico

```javascript
import SDK from 'apps-sdk';

// Obtener términos y condiciones en español
const response = await SDK.legal.getLegalText('chatconnect-ios-app', 'tc', 'es');

// Obtener política de privacidad en inglés
const response = await SDK.legal.getLegalText('chatconnect-ios-app', 'privacy_policy', 'en');

// Obtener política de reembolso en francés
const response = await SDK.legal.getLegalText('chatconnect-ios-app', 'refund_policy', 'fr');
```

### Tipos de Documentos Disponibles

| Tipo | Descripción |
|------|-------------|
| `'tc'` | Términos y Condiciones (Terms & Conditions) |
| `'contact'` | Información de Contacto Legal |
| `'privacy_policy'` | Política de Privacidad |
| `'refund_policy'` | Política de Reembolso |
| `'faqs'` | Preguntas Frecuentes (FAQs) |

### Idiomas Soportados

El parámetro `lang` acepta códigos de idioma ISO estándar:

- `'en'` - Inglés
- `'es'` - Español
- `'fr'` - Francés
- `'de'` - Alemán
- `'it'` - Italiano
- `'pt'` - Portugués
- Y otros códigos ISO estándar...

### Detalles Técnicos

**Endpoint**: `POST https://bc1742.gways.org/legal/get`

**Request Body**:
```json
{
  "type": "tc",
  "lang": "es",
  "web_id": "chatconnect-ios-app"
}
```

**Respuesta Esperada**:
```json
{
  "success": 1,
  "data": {
    "content": "Contenido del documento legal...",
    "title": "Términos y Condiciones",
    "last_updated": "2025-02-12"
  }
}
```

### Ejemplo Completo en React Native

```javascript
import React, { useEffect, useState } from 'react';
import { View, Text, ScrollView } from 'react-native';
import SDK from 'apps-sdk';

const TermsAndConditionsScreen = () => {
    const [termsContent, setTermsContent] = useState('');
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        loadTerms();
    }, []);

    const loadTerms = async () => {
        try {
            const response = await SDK.legal.getLegalText(
                'chatconnect-ios-app',
                'tc',
                'es'
            );
            
            if (response && response.success) {
                setTermsContent(response.data.content);
            }
        } catch (error) {
            console.error('Error al cargar términos:', error);
        } finally {
            setLoading(false);
        }
    };

    return (
        <ScrollView>
            {loading ? (
                <Text>Cargando...</Text>
            ) : (
                <Text>{termsContent}</Text>
            )}
        </ScrollView>
    );
};
```

### Cargar Múltiples Documentos

```javascript
const loadAllLegalDocuments = async (webId, lang) => {
    try {
        const [terms, privacy, refund, contact, faqs] = await Promise.all([
            SDK.legal.getLegalText(webId, 'tc', lang),
            SDK.legal.getLegalText(webId, 'privacy_policy', lang),
            SDK.legal.getLegalText(webId, 'refund_policy', lang),
            SDK.legal.getLegalText(webId, 'contact', lang),
            SDK.legal.getLegalText(webId, 'faqs', lang),
        ]);

        return {
            terms: terms.data,
            privacy: privacy.data,
            refund: refund.data,
            contact: contact.data,
            faqs: faqs.data,
        };
    } catch (error) {
        console.error('Error al cargar documentos legales:', error);
        throw error;
    }
};

// Uso
const legalDocs = await loadAllLegalDocuments('chatconnect-ios-app', 'es');
```

### Manejo de Errores

```javascript
const getLegalDocumentSafely = async (webId, type, lang) => {
    try {
        const response = await SDK.legal.getLegalText(webId, type, lang);
        
        if (response && response.success === 1) {
            return {
                success: true,
                content: response.data
            };
        } else {
            return {
                success: false,
                error: 'Documento no disponible'
            };
        }
    } catch (error) {
        console.error('Error al obtener documento legal:', error);
        return {
            success: false,
            error: error.message
        };
    }
};

// Uso con manejo de errores
const result = await getLegalDocumentSafely('chatconnect-ios-app', 'tc', 'es');
if (result.success) {
    console.log('Contenido:', result.content);
} else {
    console.error('Error:', result.error);
}
```

### Validaciones

El método incluye validaciones automáticas:

1. **web_id requerido**: Lanza un error si no se proporciona
2. **type requerido**: Lanza un error si no se proporciona
3. **lang requerido**: Lanza un error si no se proporciona
4. **Tipo válido**: Solo acepta los 5 tipos de documentos especificados
