/**
 * Claude Service - Chat interface with Claude AI and MCP Integration
 *
 * Provides:
 * - Direct Claude chat
 * - MCP tool execution
 * - Project context integration
 * - Integration management (Figma, Jira, Confluence)
 */

import api from '../core/api.js';
import logger from '../core/logger.js';

class ClaudeService {
  constructor() {
    this.conversationHistory = [];
    this.maxHistory = 50;
    this.currentProjectId = null;
    this.userId = 1; // Default user ID (TODO: implement proper auth)
    this.mcpTools = null;
    this.mcpStatus = null;

    // Load persisted chat history
    this.loadHistory();
  }

  /**
   * Get storage key for current user
   * @private
   */
  _getStorageKey() {
    return `ds-chat-history-user-${this.userId}`;
  }

  /**
   * Load chat history from localStorage
   * @private
   */
  loadHistory() {
    const key = this._getStorageKey();
    try {
      const stored = localStorage.getItem(key);
      if (stored) {
        this.conversationHistory = JSON.parse(stored);
        logger.info('Claude', `Loaded ${this.conversationHistory.length} messages from history`);
      }
    } catch (error) {
      logger.warn('Claude', 'Failed to load chat history, resetting', error);
      localStorage.removeItem(key);
      this.conversationHistory = [];
    }
  }

  /**
   * Save chat history to localStorage with quota management
   * @private
   */
  saveHistory() {
    const key = this._getStorageKey();
    try {
      // Keep only last 50 messages to respect localStorage limits
      const historyToSave = this.conversationHistory.slice(-50);
      localStorage.setItem(key, JSON.stringify(historyToSave));
    } catch (error) {
      logger.warn('Claude', 'Failed to save chat history', error);
      if (error.name === 'QuotaExceededError') {
        // Emergency trim: cut in half and retry
        this.conversationHistory = this.conversationHistory.slice(-25);
        try {
          localStorage.setItem(key, JSON.stringify(this.conversationHistory));
          logger.info('Claude', 'History trimmed to 25 messages due to quota');
        } catch (retryError) {
          logger.error('Claude', 'Failed to save history even after trim', retryError);
        }
      }
    }
  }

  /**
   * Set current project context
   */
  setProject(projectId) {
    this.currentProjectId = projectId;
    logger.info('Claude', 'Project context set', { projectId });
  }

  /**
   * Send message to Claude with MCP context
   */
  async chat(message, context = {}) {
    logger.info('Claude', 'Sending message', { message: message.substring(0, 50) + '...' });

    // Add project context if available
    if (this.currentProjectId && !context.projectId) {
      context.projectId = this.currentProjectId;
    }

    // Add to history
    this.conversationHistory.push({
      role: 'user',
      content: message,
      timestamp: new Date().toISOString()
    });

    try {
      // Call backend Claude endpoint with MCP context
      const response = await api.post('/claude/chat', {
        message,
        context: {
          ...context,
          mcp_enabled: true,
          available_tools: this.mcpTools ? Object.keys(this.mcpTools).flatMap(k => this.mcpTools[k].map(t => t.name)) : []
        },
        history: this.conversationHistory.slice(-10) // Send last 10 messages
      });

      // Add response to history
      this.conversationHistory.push({
        role: 'assistant',
        content: response.response,
        timestamp: new Date().toISOString(),
        tools_used: response.tools_used || []
      });

      // Keep history manageable
      if (this.conversationHistory.length > this.maxHistory) {
        this.conversationHistory = this.conversationHistory.slice(-this.maxHistory);
      }

      // Persist updated history
      this.saveHistory();

      logger.info('Claude', 'Received response', { length: response.response.length });

      return response.response;
    } catch (error) {
      logger.error('Claude', 'Chat failed', error);
      throw error;
    }
  }

  /**
   * Get conversation history
   */
  getHistory() {
    return this.conversationHistory;
  }

  /**
   * Clear history
   */
  clearHistory() {
    this.conversationHistory = [];
    this.saveHistory(); // Persist empty state
    logger.info('Claude', 'Conversation history cleared');
  }

  /**
   * Export conversation
   */
  exportConversation() {
    const data = JSON.stringify(this.conversationHistory, null, 2);
    const dataUri = 'data:application/json;charset=utf-8,' + encodeURIComponent(data);
    const exportFileDefaultName = `claude-conversation-${Date.now()}.json`;

    const linkElement = document.createElement('a');
    linkElement.setAttribute('href', dataUri);
    linkElement.setAttribute('download', exportFileDefaultName);
    linkElement.click();
  }

  // === MCP Integration Methods ===

  /**
   * Get MCP server status
   */
  async getMcpStatus() {
    try {
      const status = await api.get('/mcp/status');
      this.mcpStatus = status;
      logger.info('Claude', 'MCP status fetched', status);
      return status;
    } catch (error) {
      logger.error('Claude', 'Failed to fetch MCP status', error);
      throw error;
    }
  }

  /**
   * Get all available MCP tools
   */
  async getMcpTools() {
    try {
      const tools = await api.get('/mcp/tools');
      this.mcpTools = tools.tools;
      logger.info('Claude', 'MCP tools fetched', { count: tools.total_count });
      return tools;
    } catch (error) {
      logger.error('Claude', 'Failed to fetch MCP tools', error);
      throw error;
    }
  }

  /**
   * Execute an MCP tool directly
   */
  async executeMcpTool(toolName, args = {}) {
    if (this.currentProjectId && !args.project_id) {
      args.project_id = this.currentProjectId;
    }

    try {
      logger.info('Claude', 'Executing MCP tool', { toolName, args });
      const result = await api.post(`/mcp/tools/${toolName}/execute?user_id=${this.userId}`, args);
      logger.info('Claude', 'MCP tool executed', { toolName, success: !result.error });
      return result;
    } catch (error) {
      logger.error('Claude', 'MCP tool execution failed', error);
      throw error;
    }
  }

  // === Integration Management ===

  /**
   * Get all integration types and their health status
   */
  async getIntegrations() {
    try {
      const integrations = await api.get('/mcp/integrations');
      logger.info('Claude', 'Integrations fetched', { count: integrations.integrations.length });
      return integrations.integrations;
    } catch (error) {
      logger.error('Claude', 'Failed to fetch integrations', error);
      throw error;
    }
  }

  /**
   * Get project-specific integrations
   */
  async getProjectIntegrations(projectId = null) {
    const pid = projectId || this.currentProjectId;
    if (!pid) {
      throw new Error('No project ID specified');
    }

    try {
      const integrations = await api.get(`/projects/${pid}/integrations?user_id=${this.userId}`);
      return integrations.integrations;
    } catch (error) {
      logger.error('Claude', 'Failed to fetch project integrations', error);
      throw error;
    }
  }

  /**
   * Configure an integration for a project
   */
  async configureIntegration(integrationType, config, projectId = null) {
    const pid = projectId || this.currentProjectId;
    if (!pid) {
      throw new Error('No project ID specified');
    }

    try {
      const result = await api.post(`/projects/${pid}/integrations?user_id=${this.userId}`, {
        integration_type: integrationType,
        config,
        enabled: true
      });
      logger.info('Claude', 'Integration configured', { integrationType, projectId: pid });
      return result;
    } catch (error) {
      logger.error('Claude', 'Failed to configure integration', error);
      throw error;
    }
  }

  /**
   * Update an integration
   */
  async updateIntegration(integrationType, updates, projectId = null) {
    const pid = projectId || this.currentProjectId;
    if (!pid) {
      throw new Error('No project ID specified');
    }

    try {
      const result = await api.put(
        `/projects/${pid}/integrations/${integrationType}?user_id=${this.userId}`,
        updates
      );
      logger.info('Claude', 'Integration updated', { integrationType, projectId: pid });
      return result;
    } catch (error) {
      logger.error('Claude', 'Failed to update integration', error);
      throw error;
    }
  }

  /**
   * Delete an integration
   */
  async deleteIntegration(integrationType, projectId = null) {
    const pid = projectId || this.currentProjectId;
    if (!pid) {
      throw new Error('No project ID specified');
    }

    try {
      const result = await api.delete(
        `/projects/${pid}/integrations/${integrationType}?user_id=${this.userId}`
      );
      logger.info('Claude', 'Integration deleted', { integrationType, projectId: pid });
      return result;
    } catch (error) {
      logger.error('Claude', 'Failed to delete integration', error);
      throw error;
    }
  }

  /**
   * Toggle integration enabled/disabled
   */
  async toggleIntegration(integrationType, enabled, projectId = null) {
    return this.updateIntegration(integrationType, { enabled }, projectId);
  }

  // === Project Context Tools ===

  /**
   * Get project summary via MCP
   */
  async getProjectSummary(projectId = null) {
    return this.executeMcpTool('dss_get_project_summary', {
      project_id: projectId || this.currentProjectId,
      include_components: false
    });
  }

  /**
   * Get project health via MCP
   */
  async getProjectHealth(projectId = null) {
    return this.executeMcpTool('dss_get_project_health', {
      project_id: projectId || this.currentProjectId
    });
  }

  /**
   * List project components via MCP
   */
  async listComponents(projectId = null, filter = null) {
    const args = { project_id: projectId || this.currentProjectId };
    if (filter) {
      args.filter_name = filter;
    }
    return this.executeMcpTool('dss_list_components', args);
  }

  /**
   * Get design tokens via MCP
   */
  async getDesignTokens(projectId = null, category = null) {
    const args = { project_id: projectId || this.currentProjectId };
    if (category) {
      args.token_category = category;
    }
    return this.executeMcpTool('dss_get_design_tokens', args);
  }
}

// Singleton instance
const claudeService = new ClaudeService();

export default claudeService;
export { ClaudeService };
