/**
 * Echomark API Client
 *
 * Handles communication with the Echomark forensic watermarking API.
 * Supports marking documents (PDFs, images) with unique watermarks for leak tracking.
 */

export class EchomarkClient {
  constructor(apiUrl = null, apiToken = null, useProxy = true) {
    // Use local proxy by default to bypass CORS and SSL certificate issues
    if (useProxy) {
      this.apiUrl = apiUrl || 'http://localhost:3001/echomark';
      this.apiToken = null; // Proxy handles authentication
      this.useProxy = true;
    } else {
      // Direct connection to Echomark server (requires CORS and trusted SSL)
      this.apiUrl = apiUrl || 'https://ec2-52-8-108-29.us-west-1.compute.amazonaws.com:5345/echomark/api/v2';
      this.apiToken = apiToken; // Bearer token if authentication is enabled
      this.useProxy = false;
    }
  }

  /**
   * Set the Echomark API configuration
   */
  configure(apiUrl, apiToken = null, useProxy = true) {
    this.apiUrl = apiUrl;
    this.apiToken = apiToken;
    this.useProxy = useProxy;
  }

  /**
   * Mark a PDF document with forensic watermarks
   *
   * @param {File|Blob} pdfFile - The original PDF file
   * @param {Object} markOptions - Watermarking options
   * @returns {Promise<{markedCopy: Blob, markingSchema: Object}>}
   */
  async markPDF(pdfFile, markOptions) {
    return this._markDocument('/document/mark/pdf', pdfFile, 'application/pdf', markOptions);
  }

  /**
   * Mark an image file with forensic watermarks
   *
   * @param {File|Blob} imageFile - The original image file
   * @param {string} mimeType - The image MIME type (e.g., 'image/jpeg', 'image/png')
   * @param {Object} markOptions - Watermarking options
   * @returns {Promise<{markedCopy: Blob, markingSchema: Object}>}
   */
  async markImage(imageFile, mimeType, markOptions) {
    return this._markDocument('/document/mark/image', imageFile, mimeType, markOptions);
  }

  /**
   * Internal method to mark a document
   */
  async _markDocument(endpoint, file, contentType, markOptions) {
    console.log('[Echomark] Marking document:', {
      endpoint,
      contentType,
      recipient: markOptions.recipient,
      fileSize: file.size,
      fileName: file.name,
      apiUrl: this.apiUrl
    });

    // Build multipart form data
    const formData = new FormData();
    formData.append('original', file, 'original');
    formData.append('mark_options', JSON.stringify(markOptions));

    // Make request to Echomark API
    const headers = {};
    if (this.apiToken) {
      headers['Authorization'] = `Bearer ${this.apiToken}`;
    }

    const url = `${this.apiUrl}${endpoint}`;
    console.log('[Echomark] Making request to:', url);
    console.log('[Echomark] Headers:', headers);

    try {
      const response = await fetch(url, {
        method: 'POST',
        headers: headers,
        body: formData,
        mode: 'cors', // Explicitly set CORS mode
        credentials: 'omit' // Don't send cookies
      });

      console.log('[Echomark] Response status:', response.status);
      console.log('[Echomark] Response headers:', [...response.headers.entries()]);

      if (!response.ok) {
        const errorText = await response.text();
        console.error('[Echomark] Error response:', errorText);
        throw new Error(`Echomark API error (${response.status}): ${errorText}`);
      }

      // Parse multipart response
      const result = await this._parseMultipartResponse(response);

      console.log('[Echomark] Document marked successfully');
      return result;

    } catch (error) {
      console.error('[Echomark] Failed to mark document:', error);
      console.error('[Echomark] Error name:', error.name);
      console.error('[Echomark] Error message:', error.message);
      console.error('[Echomark] Error stack:', error.stack);
      throw error;
    }
  }

  /**
   * Detect leaked document and identify recipient
   *
   * @param {File|Blob} artifact - The leaked document/image
   * @param {Array<File|Blob>} originals - Array of possible original documents
   * @param {Object} detectOptions - Detection options (page_idx, orientation_idx, etc.)
   * @returns {Promise<{scores: Array, confidence: string}>}
   */
  async detect(artifact, originals, detectOptions = {}) {
    console.log('[Echomark] Starting leak investigation');

    const formData = new FormData();
    formData.append('artifact', artifact, 'artifact');

    // Add all original files
    originals.forEach((original, index) => {
      formData.append(`original_${index + 1}`, original, `original_${index + 1}`);
    });

    // Add detection options
    if (Object.keys(detectOptions).length > 0) {
      formData.append('detect_options', JSON.stringify(detectOptions));
    }

    const headers = {};
    if (this.apiToken) {
      headers['Authorization'] = `Bearer ${this.apiToken}`;
    }

    try {
      const response = await fetch(`${this.apiUrl}/detect/`, {
        method: 'POST',
        headers: headers,
        body: formData
      });

      if (!response.ok) {
        const errorText = await response.text();
        throw new Error(`Echomark detection error (${response.status}): ${errorText}`);
      }

      const result = await response.json();
      console.log('[Echomark] Detection complete:', result);
      return result;

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

  /**
   * Parse multipart form response from Echomark API
   * Returns {markedCopy: Blob, markingSchema: Object}
   */
  async _parseMultipartResponse(response) {
    const contentType = response.headers.get('content-type');

    if (!contentType || !contentType.includes('multipart/form-data')) {
      throw new Error('Expected multipart/form-data response from Echomark API');
    }

    // Extract boundary from content-type header
    const boundaryMatch = contentType.match(/boundary=([^;]+)/);
    if (!boundaryMatch) {
      throw new Error('No boundary found in multipart response');
    }

    const boundary = boundaryMatch[1].trim();
    const responseData = await response.arrayBuffer();
    const parts = this._parseMultipartData(responseData, boundary);

    // Extract marked_copy and marking_schema from parts
    let markedCopy = null;
    let markingSchema = null;

    for (const part of parts) {
      if (part.name === 'marked_copy') {
        markedCopy = new Blob([part.data], { type: part.contentType });
      } else if (part.name === 'marking_schema') {
        const decoder = new TextDecoder();
        const jsonText = decoder.decode(part.data);
        markingSchema = JSON.parse(jsonText);
      }
    }

    if (!markedCopy || !markingSchema) {
      throw new Error('Missing marked_copy or marking_schema in response');
    }

    return { markedCopy, markingSchema };
  }

  /**
   * Parse multipart form data
   * Returns array of {name, contentType, data}
   */
  _parseMultipartData(buffer, boundary) {
    const decoder = new TextDecoder();
    const text = decoder.decode(buffer);
    const boundaryStr = `--${boundary}`;
    const parts = [];

    // Split by boundary
    const sections = text.split(boundaryStr);

    for (const section of sections) {
      if (section.trim() === '' || section.trim() === '--') continue;

      // Parse headers and content
      const parts_split = section.split('\r\n\r\n');
      if (parts_split.length < 2) continue;

      const headers = parts_split[0];
      const content = parts_split.slice(1).join('\r\n\r\n');

      // Extract name from Content-Disposition
      const nameMatch = headers.match(/name="([^"]+)"/);
      if (!nameMatch) continue;

      const name = nameMatch[1];

      // Extract content type
      const typeMatch = headers.match(/Content-Type:\s*([^\r\n]+)/i);
      const contentType = typeMatch ? typeMatch[1].trim() : 'text/plain';

      // Convert content back to binary
      const encoder = new TextEncoder();
      const data = encoder.encode(content.trim());

      parts.push({ name, contentType, data });
    }

    return parts;
  }

  /**
   * Build mark options for Echomark API
   *
   * @param {Object} params - Parameters for watermarking
   * @returns {Object} Mark options in Echomark format
   */
  buildMarkOptions({
    recipientId,
    recipientName,
    imageWatermarking = true,
    textWatermarking = true,
    visibleWatermarking = false,
    visibleWatermarkText = 'Personalized for {{recipient}}',
    imageAlgorithm = 'auto',
    colorDistortionLimit = 3,
    spatialDistortionLimit = 5
  }) {
    return {
      recipient: recipientId,
      recipient_name: recipientName,
      image_watermarking_enabled: imageWatermarking,
      image_watermarking_options: {
        algorithm: imageAlgorithm,
        color_distortion_limit: colorDistortionLimit,
        spatial_distortion_limit: spatialDistortionLimit
      },
      text_watermarking_enabled: textWatermarking,
      text_watermarking_options: {
        rendering_intent: 'screen'
      },
      visible_watermarking_enabled: visibleWatermarking,
      visible_watermarking_options: {
        text: visibleWatermarkText,
        position: 'footnote',
        color: '000000',
        opacity: 1
      }
    };
  }

  /**
   * Test connection to Echomark API
   */
  async testConnection() {
    try {
      const response = await fetch(`${this.apiUrl}/ping`, {
        method: 'GET',
        headers: this.apiToken ? { 'Authorization': `Bearer ${this.apiToken}` } : {}
      });

      if (response.ok) {
        const data = await response.json();
        console.log('[Echomark] Connection test successful:', data);
        return true;
      }
      return false;
    } catch (error) {
      console.error('[Echomark] Connection test failed:', error);
      return false;
    }
  }
}

// Singleton instance - uses proxy by default
export const echomarkClient = new EchomarkClient(
  'http://localhost:3001/echomark',
  null,
  true // Use proxy
);
