# External Project Integration Guide

This guide shows how external projects can integrate the Vue2 Premium BBL Editor upload system into their applications.

## Quick Start

### 1. Installation

```bash
npm install your-vue2-premium-bbl-editor
```

### 2. Basic Setup

```vue
<template>
  <PremiumBblEditor
    v-model="content"
    @ready="onEditorReady"
    :config="editorConfig"
  />
</template>

<script>
import { 
  PremiumBblEditor,
  UploadManager,
  LocalStorageAdapter,
  createUploadConfig,
  integrateTipTapUpload
} from 'your-vue2-premium-bbl-editor'

export default {
  components: { PremiumBblEditor },
  data() {
    return {
      content: '<p>Start typing...</p>',
      uploadManager: null,
      editorConfig: { toolbar: { image: true } }
    }
  },
  async created() {
    const config = createUploadConfig('localStorage')
    this.uploadManager = new UploadManager(config)
    
    const adapter = new LocalStorageAdapter()
    this.uploadManager.registerAdapter(adapter)
    this.uploadManager.setDefaultAdapter('local-storage')
  },
  methods: {
    onEditorReady(editor) {
      integrateTipTapUpload(editor, this.uploadManager)
    }
  }
}
</script>
```

## Integration Patterns

### Pattern 1: Simple Integration (Recommended)

Use the `integrateTipTapUpload` helper function for automatic integration:

```javascript
import { integrateTipTapUpload } from 'your-vue2-premium-bbl-editor'

onEditorReady(editor) {
  integrateTipTapUpload(editor, this.uploadManager, {
    onStart: () => console.log('Upload started'),
    onEnd: () => console.log('Upload finished')
  })
}
```

### Pattern 2: Manual Integration

For more control, use the factory pattern:

```javascript
import { createTipTapUploadAdapterFactory } from 'your-vue2-premium-bbl-editor'

onEditorReady(editor) {
  const createUploadAdapter = createTipTapUploadAdapterFactory(this.uploadManager)
  editor.plugins.get("FileRepository").createUploadAdapter = createUploadAdapter
}
```

## Custom Upload Adapters

Create adapters for your specific backend:

```javascript
class MyCustomAdapter {
  constructor(options) {
    this.name = 'my-custom-adapter'
    this.endpoint = options.endpoint
    this.apiKey = options.apiKey
  }

  async upload(file, options = {}) {
    const formData = new FormData()
    formData.append('file', file)

    const response = await fetch(this.endpoint, {
      method: 'POST',
      headers: { 'Authorization': `Bearer ${this.apiKey}` },
      body: formData
    })

    if (!response.ok) {
      throw new Error(`Upload failed: ${response.statusText}`)
    }

    const result = await response.json()
    return {
      url: result.url,
      size: file.size,
      metadata: {
        fileName: file.name,
        fileType: file.type
      }
    }
  }
}

// Register and use
const adapter = new MyCustomAdapter({
  endpoint: '/api/upload',
  apiKey: 'your-api-key'
})
uploadManager.registerAdapter(adapter)
uploadManager.setDefaultAdapter('my-custom-adapter')
```

## Configuration Options

### Upload Configuration

```javascript
const config = createUploadConfig('adapter-name', {
  validation: {
    maxSize: 10 * 1024 * 1024, // 10MB
    allowedTypes: ['image/jpeg', 'image/png', 'video/mp4'],
    customValidator: (file) => {
      // Custom validation logic
      return file.name.length < 100
    }
  },
  retry: {
    maxAttempts: 3,
    baseDelay: 1000,
    maxDelay: 5000
  },
  progress: {
    throttleMs: 100 // Progress update frequency
  }
})
```

### Editor Configuration

```javascript
const editorConfig = {
  toolbar: {
    image: true,
    video: true,
    // Other toolbar options
  },
  // Other TipTap configuration options
}
```

## Event Handling

Listen to upload events for better user experience:

```javascript
// Progress tracking
uploadManager.on('progress', (progress) => {
  console.log(`Upload progress: ${progress.percentage}%`)
  this.uploadProgress = progress.percentage
})

// Upload completion
uploadManager.on('uploadCompleted', (event) => {
  console.log('Upload completed:', event.result.url)
  this.showSuccessMessage('File uploaded successfully!')
})

// Upload failure
uploadManager.on('uploadFailed', (event) => {
  console.error('Upload failed:', event.error.message)
  this.showErrorMessage(`Upload failed: ${event.error.message}`)
})

// Retry attempts
uploadManager.on('retryAttemptStarted', (event) => {
  console.log(`Retry attempt ${event.attempt}/${event.maxAttempts}`)
})
```

## Environment-Specific Setup

### Development Environment

```javascript
// Use local storage for development
const localAdapter = new LocalStorageAdapter({
  generateObjectUrl: true,
  persistToIndexedDB: false
})
uploadManager.registerAdapter(localAdapter)
uploadManager.setDefaultAdapter('local-storage')
```

### Production Environment

```javascript
// Use your production API
const productionAdapter = new CustomApiAdapter({
  endpoint: process.env.VUE_APP_UPLOAD_ENDPOINT,
  apiKey: process.env.VUE_APP_API_KEY
})
uploadManager.registerAdapter(productionAdapter)
uploadManager.setDefaultAdapter('custom-api')
```

## Advanced Upload System Integration

The Vue2 Premium BBL Editor includes a comprehensive upload management system with multiple adapters, retry logic, progress tracking, and error handling.

### Complete Upload System Setup

```vue
<template>
  <div class="upload-integration-demo">
    <PremiumBblEditor
      v-model="content"
      @ready="onEditorReady"
    />
    
    <!-- Upload Progress -->
    <div v-if="uploadStatus.active" class="upload-progress">
      <div class="progress-bar">
        <div 
          class="progress-fill" 
          :style="{ width: uploadStatus.progress + '%' }"
        ></div>
      </div>
      <p>{{ uploadStatus.message }} - {{ uploadStatus.progress }}%</p>
    </div>
    
    <!-- Upload Statistics -->
    <div class="upload-stats" v-if="uploadStats">
      <h4>Upload Statistics</h4>
      <p>Active Uploads: {{ uploadStats.activeUploads }}</p>
      <p>Completed: {{ uploadStats.progressStats.completed }}</p>
      <p>Failed: {{ uploadStats.progressStats.failed }}</p>
      <p>Current Adapter: {{ uploadStats.defaultAdapter }}</p>
    </div>
  </div>
</template>

<script>
import { 
  PremiumBblEditor,
  UploadManager, 
  LocalStorageAdapter,
  integrateTipTapUpload,
  createUploadConfig
} from 'your-vue2-premium-bbl-editor'

// Custom API Adapter for your backend
class CustomApiAdapter {
  constructor(config = {}) {
    this.name = 'custom-api'
    this.apiUrl = config.apiUrl || '/api/upload'
    this.headers = config.headers || {}
  }

  getName() {
    return this.name
  }

  async upload(file, options) {
    const formData = new FormData()
    formData.append('file', file)
    formData.append('uploadId', options.uploadId)

    const response = await fetch(this.apiUrl, {
      method: 'POST',
      headers: this.headers,
      body: formData
    })

    if (!response.ok) {
      throw new Error(`Upload failed: ${response.statusText}`)
    }

    const data = await response.json()
    
    return {
      success: true,
      url: data.url,
      publicUrl: data.publicUrl || data.url,
      uploadId: options.uploadId,
      size: file.size,
      adapter: this.name,
      metadata: {
        fileName: file.name,
        fileType: file.type,
        uploadedAt: new Date().toISOString()
      }
    }
  }

  supportsStrategy(strategy) {
    return strategy === 'direct'
  }

  validateConfig() {
    return true
  }
}

export default {
  components: {
    PremiumBblEditor
  },
  
  data() {
    return {
      content: '<p>Advanced upload system integration example</p>',
      uploadManager: null,
      uploadStatus: {
        active: false,
        progress: 0,
        message: ''
      },
      uploadStats: null
    }
  },
  
  async created() {
    await this.initializeUploadSystem()
  },
  
  methods: {
    async initializeUploadSystem() {
      try {
        // Create comprehensive upload configuration
        const config = createUploadConfig('localStorage', {
          validation: {
            maxSize: 10 * 1024 * 1024, // 10MB
            allowedTypes: [
              'image/jpeg', 'image/png', 'image/gif', 'image/webp',
              'video/mp4', 'video/webm', 'video/ogg'
            ],
            customValidator: (file) => {
              // Custom validation logic
              if (file.name.length > 100) {
                throw new Error('Filename too long')
              }
              return true
            }
          },
          retry: {
            maxAttempts: 3,
            baseDelay: 1000,
            maxDelay: 5000,
            backoffFactor: 2
          },
          progress: {
            throttleMs: 100 // Progress update frequency
          },
          debug: process.env.NODE_ENV === 'development'
        })
        
        // Initialize upload manager
        this.uploadManager = new UploadManager(config)
        
        // Register multiple adapters
        await this.setupAdapters()
        
        // Set up comprehensive event listeners
        this.setupEventListeners()
        
        // Update initial stats
        this.updateStats()
        
        console.log('✅ Upload system initialized successfully')
        
      } catch (error) {
        console.error('❌ Upload system initialization failed:', error)
      }
    },

    async setupAdapters() {
      // Local storage adapter for development
      const localAdapter = new LocalStorageAdapter({
        generateObjectUrl: true,
        persistToIndexedDB: false
      })
      this.uploadManager.registerAdapter(localAdapter)

      // Custom API adapter for production
      const apiAdapter = new CustomApiAdapter({
        apiUrl: process.env.VUE_APP_UPLOAD_URL || '/api/upload',
        headers: {
          'Authorization': `Bearer ${this.getAuthToken()}`,
          'X-Client-Version': '1.0.0'
        }
      })
      this.uploadManager.registerAdapter(apiAdapter)

      // Set default adapter based on environment
      const defaultAdapter = process.env.NODE_ENV === 'production' 
        ? 'custom-api' 
        : 'local-storage'
      
      this.uploadManager.setDefaultAdapter(defaultAdapter)
      
      console.log(`📡 Adapters registered, using: ${defaultAdapter}`)
    },

    setupEventListeners() {
      // Upload started
      this.uploadManager.on('uploadStarted', (event) => {
        this.uploadStatus = {
          active: true,
          progress: 0,
          message: `Starting upload: ${event.fileName}`
        }
        console.log('🚀 Upload started:', event)
      })

      // Progress tracking
      this.uploadManager.on('progress', (progress) => {
        this.uploadStatus.progress = Math.round(progress.percentage)
        this.uploadStatus.message = `Uploading: ${progress.fileName}`
        
        if (progress.speed) {
          this.uploadStatus.message += ` (${this.formatSpeed(progress.speed)})`
        }
      })

      // Upload completed
      this.uploadManager.on('uploadCompleted', (event) => {
        this.uploadStatus = {
          active: false,
          progress: 100,
          message: 'Upload completed successfully!'
        }
        
        console.log('✅ Upload completed:', event.result.url)
        
        // Clear status after delay
        setTimeout(() => {
          this.uploadStatus.active = false
        }, 2000)
        
        this.updateStats()
      })

      // Upload failed
      this.uploadManager.on('uploadFailed', (event) => {
        this.uploadStatus = {
          active: false,
          progress: 0,
          message: `Upload failed: ${event.error.message}`
        }
        
        console.error('❌ Upload failed:', event.error)
        
        // Show user-friendly error message
        this.showErrorNotification(this.getUserFriendlyError(event.error))
        
        // Clear status after delay
        setTimeout(() => {
          this.uploadStatus.active = false
        }, 5000)
        
        this.updateStats()
      })

      // Retry attempts
      this.uploadManager.on('retryAttemptStarted', (event) => {
        this.uploadStatus.message = `Retry attempt ${event.attempt}/${event.maxAttempts}`
        console.log(`🔄 Retry attempt ${event.attempt}/${event.maxAttempts}`)
      })

      // Adapter changes
      this.uploadManager.on('defaultAdapterChanged', (event) => {
        console.log(`🔄 Switched to adapter: ${event.newDefault}`)
        this.updateStats()
      })

      // Validation errors
      this.uploadManager.on('validationFailed', (event) => {
        console.warn('⚠️ Validation failed:', event.error.message)
        this.showErrorNotification(event.error.message)
      })
    },

    onEditorReady(editor) {
      console.log('📝 Editor ready, integrating upload system...')
      
      // Integrate upload system with TipTap
      integrateTipTapUpload(editor, this.uploadManager, {
        onStart: () => {
          console.log('🎬 TipTap upload integration started')
        },
        onEnd: () => {
          console.log('🎬 TipTap upload integration ended')
        }
      })

      console.log('✅ TipTap upload integration completed')
    },

    updateStats() {
      if (this.uploadManager) {
        this.uploadStats = this.uploadManager.getStats()
      }
    },

    getUserFriendlyError(error) {
      const errorMap = {
        'FILE_TOO_LARGE': 'File is too large. Please choose a smaller file.',
        'INVALID_FILE_TYPE': 'File type not supported. Please choose a different file.',
        'NETWORK_ERROR': 'Network error. Please check your connection and try again.',
        'UPLOAD_TIMEOUT': 'Upload timed out. Please try again.',
        'SERVER_ERROR': 'Server error. Please try again later.'
      }
      
      return errorMap[error.code] || error.message || 'Upload failed. Please try again.'
    },

    showErrorNotification(message) {
      // Implement your notification system
      alert(message) // Replace with your notification component
    },

    formatSpeed(bytesPerSecond) {
      const units = ['B/s', 'KB/s', 'MB/s', 'GB/s']
      let size = bytesPerSecond
      let unitIndex = 0
      
      while (size >= 1024 && unitIndex < units.length - 1) {
        size /= 1024
        unitIndex++
      }
      
      return `${size.toFixed(1)} ${units[unitIndex]}`
    },

    getAuthToken() {
      // Return your authentication token
      return localStorage.getItem('authToken') || ''
    }
  },
  
  beforeDestroy() {
    if (this.uploadManager) {
      this.uploadManager.destroy()
    }
  }
}
</script>

<style scoped>
.upload-integration-demo {
  max-width: 1000px;
  margin: 0 auto;
  padding: 20px;
}

.upload-progress {
  margin: 20px 0;
  padding: 15px;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  border-radius: 8px;
}

.progress-bar {
  width: 100%;
  height: 8px;
  background: rgba(255, 255, 255, 0.3);
  border-radius: 4px;
  margin-bottom: 10px;
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  background: white;
  border-radius: 4px;
  transition: width 0.3s ease;
}

.upload-stats {
  margin-top: 20px;
  padding: 15px;
  background: #f8f9fa;
  border: 1px solid #dee2e6;
  border-radius: 6px;
}

.upload-stats h4 {
  margin-top: 0;
  color: #495057;
}

.upload-stats p {
  margin: 5px 0;
  font-size: 14px;
  color: #6c757d;
}
</style>
```

### Upload Configuration Presets

The upload system includes pre-configured setups for common scenarios:

```javascript
// Local Storage (Development)
const localConfig = createUploadConfig('localStorage', {
  validation: {
    maxSize: 10 * 1024 * 1024, // 10MB
    allowedTypes: ['image/jpeg', 'image/png', 'image/gif', 'video/mp4']
  },
  retry: {
    maxAttempts: 2,
    baseDelay: 500
  }
})

// AWS S3 (Production)
const s3Config = createUploadConfig('awsS3', {
  adapters: {
    'aws-s3': {
      type: 'aws-s3',
      credentials: {
        accessKeyId: process.env.AWS_ACCESS_KEY_ID,
        secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
        region: 'us-east-1',
        bucket: 'my-uploads-bucket'
      },
      options: {
        forcePathStyle: false,
        usePresignedUrls: true
      }
    }
  },
  validation: {
    maxSize: 50 * 1024 * 1024, // 50MB for S3
    allowedTypes: [
      'image/jpeg', 'image/png', 'image/gif', 'image/webp',
      'video/mp4', 'video/webm', 'video/ogg'
    ]
  },
  chunking: {
    defaultChunkSize: 5 * 1024 * 1024, // 5MB chunks
    autoChunkThreshold: 10 * 1024 * 1024, // 10MB threshold
    parallelUploads: 3
  }
})

// Cloudinary (Media Management)
const cloudinaryConfig = createUploadConfig('cloudinary', {
  adapters: {
    'cloudinary': {
      type: 'cloudinary',
      credentials: {
        cloudName: 'my-cloud',
        apiKey: process.env.CLOUDINARY_API_KEY,
        apiSecret: process.env.CLOUDINARY_API_SECRET
      },
      options: {
        uploadPreset: 'my_preset',
        folder: 'editor_uploads',
        transformation: {
          quality: 'auto',
          fetch_format: 'auto'
        }
      }
    }
  },
  validation: {
    maxSize: 100 * 1024 * 1024 // 100MB for Cloudinary
  }
})
```

### Multiple Upload Strategies

```javascript
// Direct upload strategy
const directStrategy = new DirectUploadStrategy({
  endpoint: '/api/upload',
  method: 'POST',
  headers: {
    'Authorization': 'Bearer token'
  }
})

// Presigned URL strategy (for S3)
const presignedStrategy = new PresignedUrlStrategy({
  getPresignedUrl: async (file) => {
    const response = await fetch('/api/presigned-url', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        fileName: file.name,
        fileType: file.type,
        fileSize: file.size
      })
    })
    const data = await response.json()
    return data.presignedUrl
  }
})

// Register strategies with upload manager
uploadManager.registerStrategy('direct', directStrategy)
uploadManager.registerStrategy('presigned', presignedStrategy)
```

## Error Handling

Implement robust error handling:

```javascript
uploadManager.on('uploadFailed', (event) => {
  const { error, uploadId, adapter } = event
  
  // Log for debugging
  console.error('Upload failed:', {
    uploadId,
    adapter,
    error: error.message,
    stack: error.stack
  })
  
  // Show user-friendly message
  let userMessage = 'Upload failed. Please try again.'
  
  if (error.code === 'FILE_TOO_LARGE') {
    userMessage = 'File is too large. Please choose a smaller file.'
  } else if (error.code === 'INVALID_FILE_TYPE') {
    userMessage = 'File type not supported. Please choose a different file.'
  } else if (error.code === 'NETWORK_ERROR') {
    userMessage = 'Network error. Please check your connection and try again.'
  }
  
  this.showErrorNotification(userMessage)
})
```

## TypeScript Support

If using TypeScript, import types:

```typescript
import { 
  UploadManager,
  UploadConfig,
  UploadAdapter,
  UploadResult
} from 'your-vue2-premium-bbl-editor'

interface CustomAdapterOptions {
  endpoint: string
  apiKey: string
}

class CustomAdapter implements UploadAdapter {
  name = 'custom-adapter'
  
  constructor(private options: CustomAdapterOptions) {}
  
  async upload(file: File): Promise<UploadResult> {
    // Implementation
  }
}
```

## Best Practices

1. **Always handle errors gracefully** - Show user-friendly error messages
2. **Provide upload progress feedback** - Users expect to see progress
3. **Validate files before upload** - Use the built-in validation system
4. **Use appropriate adapters** - Local storage for dev, cloud services for production
5. **Clean up resources** - Call `uploadManager.destroy()` when component unmounts
6. **Test with different file types and sizes** - Ensure your validation works correctly

## Troubleshooting

### Common Issues

1. **Upload not working**: Check if adapter is registered and set as default
2. **Files not appearing in editor**: Ensure the upload result returns a valid URL
3. **Progress not updating**: Check if progress events are being emitted
4. **Memory issues**: Use appropriate file size limits and clean up resources

### Debug Mode

Enable debug logging:

```javascript
const config = createUploadConfig('adapter-name', {
  debug: true // Enables detailed logging
})
```

## Examples

See the `examples/` directory for complete working examples:

- `examples/external-project-integration.vue` - Basic integration
- `examples/custom-adapter-integration.vue` - Custom adapter example
- `examples/tiptap-integration-example.vue` - Full-featured example

## Support

For issues and questions:
1. Check the troubleshooting section
2. Review the examples
3. Open an issue on GitHub
4. Check the API documentation