/**
 * Filevine Upload Service
 * Handles uploading documents back to Filevine via S3
 */

export class FilevineUploadService {
  constructor(webApiClient, authManager) {
    this.webApiClient = webApiClient;
    this.authManager = authManager;
  }

  /**
   * Upload a document to Filevine
   * @param {Object} options
   * @param {Blob|File} options.file - File to upload
   * @param {string} options.filename - Filename
   * @param {string} options.projectId - Project ID
   * @param {string} options.folderId - Folder ID (optional, defaults to root)
   * @param {Function} options.onProgress - Progress callback (0-100)
   * @returns {Promise<Object>} Upload result with docId
   */
  async uploadDocument({ file, filename, projectId, folderId = null, onProgress = () => {} }) {
    console.log('[Filevine Upload] Starting upload:', filename, 'to project:', projectId, 'folder:', folderId);

    try {
      // Step 1: Get S3 credentials
      onProgress(10);
      const s3Credentials = await this.getS3Credentials();
      console.log('[Filevine Upload] Got S3 credentials');

      // Step 2: Get upload key from Filevine
      onProgress(20);
      const fileSize = file.size;
      const uploadKeyResponse = await this.getUploadKey({
        filename,
        size: fileSize,
        projectId,
        folderId
      });

      console.log('[Filevine Upload] Got upload key:', uploadKeyResponse.key);

      // Step 3: Upload file to S3
      onProgress(30);
      await this.uploadToS3({
        file,
        key: uploadKeyResponse.key,
        bucket: uploadKeyResponse.bucket,
        uploadUrl: uploadKeyResponse.uploadUrl,  // Pass pre-signed URL if available
        credentials: s3Credentials,
        onProgress: (s3Progress) => {
          // Map S3 progress (30-80) to overall progress
          onProgress(30 + (s3Progress * 0.5));
        }
      });

      console.log('[Filevine Upload] File uploaded to S3');

      // Step 4: Claim document for project
      onProgress(90);
      const docId = uploadKeyResponse.docId;
      await this.claimDocumentForProject(docId, projectId);

      console.log('[Filevine Upload] Document claimed for project, docId:', docId);

      onProgress(100);

      return {
        success: true,
        docId,
        filename
      };

    } catch (error) {
      console.error('[Filevine Upload] Upload failed:', error);
      throw error;
    }
  }

  /**
   * Get S3 credentials from Filevine
   */
  async getS3Credentials() {
    if (!this.webApiClient.isAuthenticated()) {
      throw new Error('Not authenticated');
    }

    try {
      const response = await this.webApiClient.request('GET', '/docs/s3credentials');

      console.log('[Filevine Upload] S3 credentials response:', response);

      if (!response || !response.accessKeyId) {
        throw new Error('Failed to get S3 credentials - invalid response format');
      }

      return {
        accessKeyId: response.accessKeyId,
        secretAccessKey: response.secretAccessKey,
        sessionToken: response.sessionToken,
        useAccelerated: response.useAccelerated || false,
        region: response.region || 'us-east-1'
      };
    } catch (error) {
      console.error('[Filevine Upload] Failed to get S3 credentials:', error);
      throw new Error(`Failed to get S3 credentials: ${error.message}`);
    }
  }

  /**
   * Get upload key from Filevine
   */
  async getUploadKey({ filename, size, projectId, folderId }) {
    if (!this.webApiClient.isAuthenticated()) {
      throw new Error('Not authenticated');
    }

    const payload = {
      filename,
      size,
      projectID: parseInt(projectId, 10)
    };

    // Add folder ID if provided
    if (folderId) {
      payload.folderID = parseInt(folderId, 10);
    }

    console.log('[Filevine Upload] Requesting upload key with payload:', payload);

    try {
      const response = await this.webApiClient.request('POST', '/docs/uploadkey', { data: payload });

      console.log('[Filevine Upload] Upload key response:', response);
      console.log('[Filevine Upload] Response keys:', Object.keys(response));
      console.log('[Filevine Upload] Full response:', JSON.stringify(response, null, 2));

      if (!response || !response.key) {
        throw new Error('Failed to get upload key');
      }

      return {
        key: response.key,
        docId: response.docId,
        bucket: response.bucket,
        uploadUrl: response.uploadUrl || response.url || response.presignedUrl  // Check for pre-signed URL
      };
    } catch (error) {
      console.error('[Filevine Upload] Failed to get upload key:', error);
      throw new Error(`Failed to get upload key: ${error.message}`);
    }
  }

  /**
   * Upload file to S3
   */
  async uploadToS3({ file, key, bucket, uploadUrl, credentials, onProgress = () => {} }) {
    let s3Url;
    let headers = {};

    // If we have a pre-signed URL from Filevine, use that (preferred method)
    if (uploadUrl) {
      s3Url = uploadUrl;
      console.log('[Filevine Upload] Using pre-signed URL from uploadKey response');
      console.log('[Filevine Upload] Pre-signed URL:', s3Url.substring(0, 100) + '...');

      // Pre-signed URLs have auth in the URL itself, just need Content-Type
      headers['Content-Type'] = file.type || 'application/octet-stream';
    } else {
      // Fallback: construct S3 URL manually and use session token
      console.log('[Filevine Upload] No pre-signed URL, constructing S3 URL manually');

      const { accessKeyId, secretAccessKey, sessionToken, region } = credentials;

      // Bucket might not be in uploadKey response, use default Filevine bucket
      if (!bucket) {
        bucket = 'filevine-files';
        console.log('[Filevine Upload] Using default bucket:', bucket);
      }

      // Build S3 URL - use standard endpoint (acceleration not configured on this bucket)
      s3Url = `https://${bucket}.s3.${region}.amazonaws.com/${key}`;

      // Add AWS authentication headers
      headers['x-amz-security-token'] = sessionToken;
      headers['Content-Type'] = file.type || 'application/octet-stream';
    }

    console.log('[Filevine Upload] Uploading to:', s3Url.substring(0, 100) + '...');
    console.log('[Filevine Upload] File size:', file.size, 'bytes');
    console.log('[Filevine Upload] File type:', file.type);

    try {
      // Use fetch API (XMLHttpRequest is not available in service workers)
      const response = await fetch(s3Url, {
        method: 'PUT',
        headers: headers,
        body: file
      });

      if (!response.ok) {
        const errorText = await response.text();
        console.error('[Filevine Upload] S3 upload failed:', response.status, response.statusText);
        console.error('[Filevine Upload] Error response:', errorText.substring(0, 500));
        throw new Error(`S3 upload failed: ${response.status} ${response.statusText}`);
      }

      console.log('[Filevine Upload] S3 upload complete');
      onProgress(100);
    } catch (error) {
      console.error('[Filevine Upload] S3 upload error:', error);
      throw new Error(`S3 upload failed: ${error.message}`);
    }
  }

  /**
   * Claim document for project
   */
  async claimDocumentForProject(docId, projectId) {
    if (!this.webApiClient.isAuthenticated()) {
      throw new Error('Not authenticated');
    }

    const response = await this.webApiClient.request(
      'POST',
      `/docs/${docId}/claimForProject/${projectId}`
    );

    console.log('[Filevine Upload] Claim response:', response);

    return response;
  }
}

// Singleton instance
let uploadServiceInstance = null;

export function getFilevineUploadService(webApiClient, authManager) {
  if (!uploadServiceInstance) {
    uploadServiceInstance = new FilevineUploadService(webApiClient, authManager);
  }
  return uploadServiceInstance;
}
