// src/ckeditor/FirebaseUploadAdapter.ts
import {
  getStorage,
  ref,
  uploadBytesResumable,
  getDownloadURL,
  type StorageReference,
  type UploadTask,
  type FirebaseStorage,
} from 'firebase/storage';
import type { FirebaseError } from 'firebase/app'; // Import FirebaseError type
import { v4 as uuidv4 } from 'uuid';

// Import CKEditor types (optional, use any if types are problematic)
import type { Editor } from '@ckeditor/ckeditor5-core';
import type { FileLoader } from '@ckeditor/ckeditor5-upload/src/filerepository'; // More specific type

class FirebaseUploadAdapter {
  // CKEditor FileLoader instance
  private loader: FileLoader; // Or MinimalFileLoader or any
  // Firebase Storage instance
  private storage: FirebaseStorage;
  // Firebase Storage reference for the current upload
  private storageRef?: StorageReference;
  // Firebase Upload task for the current upload
  private uploadTask?: UploadTask;

  constructor(loader: FileLoader) {
    // Or MinimalFileLoader or any
    this.loader = loader;
    this.storage = getStorage(); // Get Firebase storage instance
  }

  /**
   * Starts the upload process.
   * Returns a Promise that resolves with the uploaded image's data object
   * required by CKEditor ({ default: 'image_url' }).
   */
  public async upload(): Promise<{ default: string }> {
    try {
      const file = await this.loader.file;

      if (!file) {
        throw new Error('File not found in CKEditor loader.');
      }

      // --- 1. Generate unique filename ---
      const fileExtension = file.name.split('.').pop() || 'file'; // Handle cases with no extension
      const uniqueFileName = `${uuidv4()}.${fileExtension}`;
      const storagePath = `ckeditor_uploads/${uniqueFileName}`; // Adjust path as needed
      this.storageRef = ref(this.storage, storagePath);

      // --- 2. Create the upload task ---
      this.uploadTask = uploadBytesResumable(this.storageRef, file);

      // --- 3. Return a promise that resolves on success/rejects on error ---
      return new Promise((resolve, reject) => {
        this.uploadTask?.on(
          'state_changed',
          (snapshot) => {
            // Progress monitoring (optional)
            const progress =
              (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
            console.log(`Upload is ${progress}% done`);
            // Update CKEditor loader progress (optional)
            // this.loader.uploadTotal = snapshot.totalBytes;
            // this.loader.uploaded = snapshot.bytesTransferred;
          },
          (error: unknown) => {
            // Use unknown for generic error catching
            // Handle unsuccessful uploads
            console.error('Firebase upload error:', error);
            let errorMessage = 'Upload failed due to an unknown error.';
            // Check if it's a FirebaseError for specific codes
            if (
              typeof error === 'object' &&
              error !== null &&
              'code' in error
            ) {
              const firebaseError = error as FirebaseError; // Type assertion
              errorMessage = `Upload failed: ${firebaseError.code} - ${firebaseError.message}`;
            } else if (error instanceof Error) {
              errorMessage = `Upload failed: ${error.message}`;
            }
            reject(errorMessage); // Reject the promise
          },
          async () => {
            // Use async here for await getDownloadURL
            // Handle successful uploads on complete
            try {
              console.log('Upload successful!');
              if (!this.uploadTask?.snapshot.ref) {
                throw new Error('Upload task snapshot reference is missing.');
              }
              const downloadURL = await getDownloadURL(
                this.uploadTask.snapshot.ref
              );
              console.log('File available at', downloadURL);
              // Resolve the promise with the file data CKEditor expects
              resolve({
                default: downloadURL,
              });
            } catch (error: unknown) {
              console.error('Error getting download URL:', error);
              const message =
                error instanceof Error ? error.message : String(error);
              reject(`Could not get download URL: ${message}`);
            }
          }
        );
      });
    } catch (error: unknown) {
      console.error('Error initiating upload:', error);
      const message = error instanceof Error ? error.message : String(error);
      // Ensure the promise returned by upload() is rejected
      return Promise.reject(`Error initiating upload: ${message}`);
    }
  }

  /**
   * Aborts the upload process.
   */
  public abort(): void {
    if (this.uploadTask) {
      console.log('Aborting Firebase upload...');
      this.uploadTask.cancel();
    }
  }
}

/**
 * CKEditor plugin factory function that integrates the FirebaseUploadAdapter.
 */
export default function FirebaseUploadAdapterPlugin(editor: Editor): void {
  // Use Editor type or any
  // Check if the FileRepository plugin is loaded
  if (!editor.plugins.has('FileRepository')) {
    console.error(
      'FileRepository plugin is required for FirebaseUploadAdapterPlugin.'
    );
    return;
  }

  // Register the custom adapter factory
  (editor.plugins.get('FileRepository') as any).createUploadAdapter = (
    loader: FileLoader
  ) => {
    // Match loader type
    // Configure the adapter during creation.
    return new FirebaseUploadAdapter(loader);
  };
}
