/**
 * AI Service for generating custom field configurations using Claude API
 */

import { config } from '../config/environment.js';

export class AIService {
  constructor() {
    this.apiKey = null;
    this.proxyUrl = config.proxyUrl;
    this.proxyAuthToken = config.proxyAuthToken;
    this.apiUrl = 'https://api.anthropic.com/v1/messages';
    this.model = 'claude-sonnet-4-5-20250929';
    this.nativeHostName = 'com.filevine.ai_proxy';
    this.useNativeMessaging = false; // Disabled - not implemented yet
    this.useProxy = true; // Use proxy by default (required for CORS)
    this.nativePort = null;

    console.log('[AI Service] Initialized with proxy:', this.proxyUrl);
  }

  /**
   * Set the Anthropic API key
   */
  setApiKey(apiKey) {
    this.apiKey = apiKey;
    console.log('[AI Service] API key configured');
  }

  /**
   * Check if API key is configured
   */
  isConfigured() {
    return !!this.apiKey;
  }

  /**
   * Generate custom field configurations from plain text requirements
   */
  async generateFields(requirements, context = {}) {
    if (!this.isConfigured()) {
      throw new Error('AI Service not configured. Please set API key first.');
    }

    console.log('[AI Service] Generating fields from requirements:', requirements);

    const systemPrompt = this.buildSystemPrompt();
    const userPrompt = this.buildUserPrompt(requirements, context);

    try {
      // Use XMLHttpRequest instead of fetch to bypass CORS in Chrome extensions
      const response = await this.makeAnthropicRequest({
        model: this.model,
        max_tokens: 4096,
        system: systemPrompt,
        messages: [
          {
            role: 'user',
            content: userPrompt
          }
        ]
      });

      const content = response.content[0].text;

      console.log('[AI Service] Raw AI response:', content);

      // Parse the JSON response from Claude
      const fields = this.parseFieldsResponse(content);

      console.log('[AI Service] ✅ Generated', fields.length, 'field configurations');
      return fields;

    } catch (error) {
      console.error('[AI Service] Error generating fields:', error);
      throw error;
    }
  }

  /**
   * Make a request to Anthropic API (via native messaging, proxy, or direct)
   */
  async makeAnthropicRequest(body) {
    // Try native messaging first if enabled
    if (this.useNativeMessaging) {
      try {
        console.log('[AI Service] Attempting native messaging request');
        return await this.makeNativeMessagingRequest(body);
      } catch (error) {
        console.warn('[AI Service] Native messaging failed:', error.message);
        console.log('[AI Service] Falling back to proxy...');
        this.useNativeMessaging = false; // Disable for this session
      }
    }

    // Try proxy if enabled
    if (this.useProxy) {
      try {
        console.log('[AI Service] Attempting proxy request to:', this.proxyUrl);
        return await this.makeProxyRequest(body);
      } catch (error) {
        console.warn('[AI Service] Proxy request failed:', error.message);
        console.log('[AI Service] Falling back to direct API call...');
        this.useProxy = false; // Disable proxy for future requests this session
      }
    }

    // Fall back to direct API call
    return await this.makeDirectRequest(body);
  }

  /**
   * Make request via native messaging host
   */
  async makeNativeMessagingRequest(body) {
    console.log('[AI Service] Making native messaging request');

    return new Promise((resolve, reject) => {
      try {
        // Connect to native messaging host
        const port = chrome.runtime.connectNative(this.nativeHostName);

        let responseReceived = false;

        port.onMessage.addListener((response) => {
          console.log('[AI Service] Native host response:', response);
          responseReceived = true;

          if (response.error) {
            reject(new Error(response.error));
          } else if (response.success) {
            resolve(response.data);
          } else {
            reject(new Error('Invalid response from native host'));
          }

          port.disconnect();
        });

        port.onDisconnect.addListener(() => {
          if (!responseReceived) {
            const error = chrome.runtime.lastError;
            if (error) {
              console.error('[AI Service] Native host disconnected with error:', error);
              reject(new Error(`Native host error: ${error.message}`));
            } else {
              console.error('[AI Service] Native host disconnected unexpectedly');
              reject(new Error('Native host disconnected without response'));
            }
          }
        });

        // Send the request
        console.log('[AI Service] Sending message to native host');
        port.postMessage({
          type: 'anthropic_request',
          body: body
        });

      } catch (error) {
        console.error('[AI Service] Native messaging error:', error);
        reject(new Error(`Native messaging failed: ${error.message}`));
      }
    });
  }

  /**
   * Make request via local proxy server (with authentication)
   */
  async makeProxyRequest(body) {
    console.log('[AI Service] Making authenticated proxy request');

    try {
      const response = await fetch(this.proxyUrl, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Extension-Auth': this.proxyAuthToken  // Add authentication token
        },
        body: JSON.stringify(body)
      });

      console.log('[AI Service] Proxy response status:', response.status);

      if (!response.ok) {
        const errorText = await response.text();
        let errorData;
        try {
          errorData = JSON.parse(errorText);
        } catch {
          errorData = { message: errorText };
        }

        // Special handling for auth errors
        if (response.status === 401) {
          throw new Error('Authentication required - proxy auth token missing');
        }
        if (response.status === 403) {
          throw new Error('Authentication failed - invalid proxy auth token');
        }

        throw new Error(`Proxy Error (${response.status}): ${errorData.error?.message || errorData.message || response.statusText}`);
      }

      const data = await response.json();
      console.log('[AI Service] ✅ Proxy request successful');
      return data;

    } catch (error) {
      if (error.message.includes('Failed to fetch')) {
        throw new Error('Proxy server not running. Start it with: cd proxy-server && npm start');
      }
      throw error;
    }
  }

  /**
   * Make direct request to Anthropic API
   */
  async makeDirectRequest(body) {
    console.log('[AI Service] Making direct request to:', this.apiUrl);
    console.log('[AI Service] Request body:', JSON.stringify(body, null, 2));

    try {
      const response = await fetch(this.apiUrl, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'x-api-key': this.apiKey,
          'anthropic-version': '2023-06-01',
          'anthropic-dangerous-direct-browser-access': 'true'
        },
        body: JSON.stringify(body)
      });

      console.log('[AI Service] Response status:', response.status);
      console.log('[AI Service] Response ok:', response.ok);

      if (!response.ok) {
        const errorText = await response.text();
        console.error('[AI Service] Error response:', errorText);

        let errorData;
        try {
          errorData = JSON.parse(errorText);
        } catch {
          errorData = { message: errorText };
        }

        throw new Error(`AI API Error (${response.status}): ${errorData.error?.message || errorData.message || response.statusText}`);
      }

      const data = await response.json();
      console.log('[AI Service] Response data:', data);
      return data;

    } catch (error) {
      console.error('[AI Service] Request failed:', error);

      if (error.message.includes('AI API Error')) {
        throw error;
      }

      throw new Error(`Network error calling Anthropic API: ${error.message}`);
    }
  }

  /**
   * Build the system prompt for Claude
   */
  buildSystemPrompt() {
    return `You are an expert at designing Filevine custom field schemas. Your task is to analyze user requirements and generate a structured list of custom field configurations.

Available Field Types (with their numeric IDs):
1 = Amount - Number
2 = Amount - Currency like $0.00
3 = Text - Single Line
4 = Date
5 = Yes/No
6 = Text - Multiple Lines
7 = Person
8 = File Attachment
9 = Dropdown List
10 = Sub Section Header
11 = Multiple File Attachments (List)
12 = Doc Generation
13 = Amount - Decimal like 0.00
14 = Amount - Percent like 0.00%
15 = Deadline (with reminders)
17 = Text - Multiple Lines(large)
18 = Incident Date
19 = Case Number
20 = Action Button
21 = Instructions
22 = Url
23 = Url List
24 = Text - Single Line List
25 = Person List
26 = Multi-Select List
27 = Project Link
28 = Project Link List
29 = Doc Generation Multi-template
101 = Calculated Number
102 = Calculated Currency
113 = Calculated Decimal
114 = Calculated Percentage
150 = Reference Field
1009 = Report Fusion
1010 = Report Fusion Multi-template
1100 = Outlaw Template

Rules:
1. Choose the most appropriate field type for each piece of data
2. Use clear, descriptive field names
3. Create simple, lowercase fieldSelectors (no spaces, use underscores)
4. Mark critical fields as required
5. Number rows sequentially starting from 1
6. Set orderInRow starting from 0 for the first field in each row (fields in the same row have different orderInRow values)
7. Use Sub Section Headers (type 10) to organize related fields
8. Add helpful notes to clarify the purpose of complex fields
9. For lists of items, use appropriate list field types (24, 25, 26, etc.)
10. For Dropdown List (type 9) and Multi-Select List (type 26) fields, ALWAYS include a dropdownItems array with the options

Output Format:
Return ONLY a valid JSON array of field objects. Each field object must have this exact structure:
{
  "name": "Field Display Name",
  "fieldSelector": "field_selector_name",
  "customFieldType": 3,
  "row": 1,
  "orderInRow": 0,
  "isRequired": false,
  "notes": "Optional description of the field",
  "dropdownItems": []
}

For Dropdown Lists (type 9) and Multi-Select Lists (type 26), the dropdownItems field is REQUIRED:
{
  "name": "State",
  "fieldSelector": "state",
  "customFieldType": 9,
  "row": 1,
  "orderInRow": 0,
  "isRequired": false,
  "notes": "Select the state",
  "dropdownItems": ["California", "Texas", "New York", "Florida"]
}

Layout Notes:
- "row" determines vertical position (which row the field appears in)
- "orderInRow" determines horizontal position within that row (0 = leftmost)
- Fields with the same row number but different orderInRow values appear side-by-side
- Most fields should have orderInRow: 0 unless you want multiple fields on the same row

Important:
- Return ONLY the JSON array, no other text
- Do not include markdown code blocks or formatting
- Ensure the JSON is valid and parseable
- Use appropriate field types based on the data being collected
- ALWAYS include dropdownItems array for dropdown/multi-select fields (even if empty)
- For non-dropdown fields, dropdownItems should be an empty array []
- ALWAYS include orderInRow (typically 0 unless placing multiple fields on the same row)`;
  }

  /**
   * Build the user prompt with requirements and context
   */
  buildUserPrompt(requirements, context) {
    let prompt = `Generate custom field configurations for the following requirements:\n\n${requirements}`;

    if (context.sectionName) {
      prompt += `\n\nThese fields will be added to the section: ${context.sectionName}`;
    }

    if (context.existingFields && context.existingFields.length > 0) {
      prompt += `\n\nExisting fields in this section: ${context.existingFields.map(f => f.name).join(', ')}`;
      prompt += '\n\nAvoid duplicating these fields.';
    }

    return prompt;
  }

  /**
   * Parse the fields response from Claude
   */
  parseFieldsResponse(content) {
    try {
      // Remove any markdown code blocks if present
      let jsonStr = content.trim();

      // Remove ```json and ``` markers if present
      if (jsonStr.startsWith('```')) {
        jsonStr = jsonStr.replace(/^```(?:json)?\s*/i, '').replace(/```\s*$/, '');
      }

      // Parse the JSON
      const fields = JSON.parse(jsonStr);

      if (!Array.isArray(fields)) {
        throw new Error('Response is not an array');
      }

      // Validate each field has required properties
      fields.forEach((field, index) => {
        if (!field.name || !field.fieldSelector || !field.customFieldType) {
          throw new Error(`Field at index ${index} is missing required properties`);
        }
      });

      return fields;

    } catch (error) {
      console.error('[AI Service] Failed to parse fields response:', error);
      console.error('[AI Service] Raw content:', content);
      throw new Error(`Failed to parse AI response: ${error.message}`);
    }
  }

  /**
   * Store API key in Chrome storage
   */
  async saveApiKey(apiKey) {
    await chrome.storage.local.set({ anthropicApiKey: apiKey });
    this.setApiKey(apiKey);
    console.log('[AI Service] API key saved to storage');
  }

  /**
   * Load API key from Chrome storage
   */
  async loadApiKey() {
    const result = await chrome.storage.local.get('anthropicApiKey');
    if (result.anthropicApiKey) {
      this.setApiKey(result.anthropicApiKey);
      console.log('[AI Service] API key loaded from storage');
      return true;
    }
    return false;
  }

  /**
   * Clear stored API key
   */
  async clearApiKey() {
    await chrome.storage.local.remove('anthropicApiKey');
    this.apiKey = null;
    console.log('[AI Service] API key cleared');
  }
}
