import axios from 'axios';
import { authService } from './authService';
import { config } from '../config/env';

const API_BASE_URL = config.apiBaseUrl;

// Create axios instance with auth interceptor
const apiClient = axios.create({
  baseURL: API_BASE_URL,
  timeout: 300000, // 5 minutes
});

// Add auth token to requests
apiClient.interceptors.request.use(async (config) => {
  const token = await authService.getToken();
  console.log('🔐 Auth interceptor - Token available:', !!token);
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
    console.log('🔐 Auth interceptor - Token set in headers');
  } else {
    console.warn('⚠️ Auth interceptor - No token available');
  }
  return config;
});

// Handle auth errors with retry logic
apiClient.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config;
    
    if (error.response?.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true;
      
      try {
        // Attempt to refresh the token
        const newToken = await authService.getToken();
        if (newToken) {
          // Retry the original request with the new token
          originalRequest.headers.Authorization = `Bearer ${newToken}`;
          return apiClient(originalRequest);
        }
      } catch (refreshError) {
        console.error('Token refresh failed:', refreshError);
      }
      
      // If token refresh fails, logout the user
      authService.logout();
      window.location.href = '/login';
    }
    
    return Promise.reject(error);
  }
);

export interface Document {
  id: string;
  user_id: string;
  original_file_name: string;
  file_path: string;
  file_size: number;
  uploaded_at: string;
  status: 'uploading' | 'uploaded' | 'extracting_text' | 'processing_llm' | 'generating_pdf' | 'completed' | 'failed';
  extracted_text?: string;
  generated_summary?: string;
  summary_markdown_path?: string;
  summary_pdf_path?: string;
  processing_started_at?: string;
  processing_completed_at?: string;
  error_message?: string;
  analysis_data?: any; // BPCP CIM Review Template data
  created_at: string;
  updated_at: string;
  // GCS-specific fields
  gcs_path?: string;
  gcs_url?: string;
  storage_type?: 'gcs' | 'local';
}

export interface UploadProgress {
  documentId: string;
  progress: number;
  status: 'uploading' | 'processing' | 'completed' | 'error';
  message?: string;
}

export interface CIMReviewData {
  dealOverview: {
    targetCompanyName: string;
    industrySector: string;
    geography: string;
    dealSource: string;
    transactionType: string;
    dateCIMReceived: string;
    dateReviewed: string;
    reviewers: string;
    cimPageCount: string;
    statedReasonForSale: string;
  };
  businessDescription: {
    coreOperationsSummary: string;
    keyProductsServices: string;
    uniqueValueProposition: string;
    customerBaseOverview: {
      keyCustomerSegments: string;
      customerConcentrationRisk: string;
      typicalContractLength: string;
    };
    keySupplierOverview: {
      dependenceConcentrationRisk: string;
    };
  };
  marketIndustryAnalysis: {
    estimatedMarketSize: string;
    estimatedMarketGrowthRate: string;
    keyIndustryTrends: string;
    competitiveLandscape: {
      keyCompetitors: string;
      targetMarketPosition: string;
      basisOfCompetition: string;
    };
    barriersToEntry: string;
  };
  financialSummary: {
    financials: {
      fy3: { revenue: string; revenueGrowth: string; grossProfit: string; grossMargin: string; ebitda: string; ebitdaMargin: string };
      fy2: { revenue: string; revenueGrowth: string; grossProfit: string; grossMargin: string; ebitda: string; ebitdaMargin: string };
      fy1: { revenue: string; revenueGrowth: string; grossProfit: string; grossMargin: string; ebitda: string; ebitdaMargin: string };
      ltm: { revenue: string; revenueGrowth: string; grossProfit: string; grossMargin: string; ebitda: string; ebitdaMargin: string };
    };
    qualityOfEarnings: string;
    revenueGrowthDrivers: string;
    marginStabilityAnalysis: string;
    capitalExpenditures: string;
    workingCapitalIntensity: string;
    freeCashFlowQuality: string;
  };
  managementTeamOverview: {
    keyLeaders: string;
    managementQualityAssessment: string;
    postTransactionIntentions: string;
    organizationalStructure: string;
  };
  preliminaryInvestmentThesis: {
    keyAttractions: string;
    potentialRisks: string;
    valueCreationLevers: string;
    alignmentWithFundStrategy: string;
  };
  keyQuestionsNextSteps: {
    criticalQuestions: string;
    missingInformation: string;
    preliminaryRecommendation: string;
    rationaleForRecommendation: string;
    proposedNextSteps: string;
  };
}

// GCS-specific error types
export interface GCSError {
  type: 'gcs_upload_error' | 'gcs_download_error' | 'gcs_permission_error' | 'gcs_quota_error' | 'gcs_network_error';
  message: string;
  details?: any;
  retryable: boolean;
}

// Enhanced error handling for GCS operations
export class GCSErrorHandler {
  static isGCSError(error: any): error is GCSError {
    return error && typeof error === 'object' && 'type' in error && error.type?.startsWith('gcs_');
  }

  static createGCSError(error: any, operation: string): GCSError {
    const errorMessage = error?.message || error?.toString() || 'Unknown GCS error';
    
    // Determine error type based on error message or response
    let type: GCSError['type'] = 'gcs_network_error';
    let retryable = true;

    if (errorMessage.includes('permission') || errorMessage.includes('access denied')) {
      type = 'gcs_permission_error';
      retryable = false;
    } else if (errorMessage.includes('quota') || errorMessage.includes('storage quota')) {
      type = 'gcs_quota_error';
      retryable = false;
    } else if (errorMessage.includes('upload') || errorMessage.includes('write')) {
      type = 'gcs_upload_error';
      retryable = true;
    } else if (errorMessage.includes('download') || errorMessage.includes('read')) {
      type = 'gcs_download_error';
      retryable = true;
    }

    return {
      type,
      message: `${operation} failed: ${errorMessage}`,
      details: error,
      retryable
    };
  }

  static getErrorMessage(error: GCSError): string {
    switch (error.type) {
      case 'gcs_permission_error':
        return 'Access denied. Please check your permissions and try again.';
      case 'gcs_quota_error':
        return 'Storage quota exceeded. Please contact support.';
      case 'gcs_upload_error':
        return 'Upload failed. Please check your connection and try again.';
      case 'gcs_download_error':
        return 'Download failed. Please try again later.';
      case 'gcs_network_error':
        return 'Network error. Please check your connection and try again.';
      default:
        return error.message;
    }
  }
}

class DocumentService {
  /**
   * Upload a document using Firebase Storage direct upload (new method)
   */
  async uploadDocument(
    file: File, 
    onProgress?: (progress: number) => void, 
    signal?: AbortSignal
  ): Promise<Document> {
    try {
      // Check authentication before upload
      const token = await authService.getToken();
      if (!token) {
        throw new Error('Authentication required. Please log in to upload documents.');
      }

      console.log('📤 Starting Firebase Storage direct upload...');
      console.log('📤 File:', file.name, 'Size:', file.size, 'Type:', file.type);
      console.log('📤 Token available:', !!token);

      // Step 1: Get signed upload URL
      onProgress?.(5); // 5% - Getting upload URL
      
      console.log('🌐 Making request to upload-url endpoint');
      console.log('🌐 Base URL:', API_BASE_URL);
      console.log('🌐 Full URL would be:', `${API_BASE_URL}/documents/upload-url`);
      console.log('🌐 Request payload:', { fileName: file.name, fileSize: file.size, contentType: file.type });
      
      const uploadUrlResponse = await apiClient.post('/documents/upload-url', {
        fileName: file.name,
        fileSize: file.size,
        contentType: file.type
      }, { signal });

      const { documentId, uploadUrl } = uploadUrlResponse.data;
      console.log('✅ Got signed upload URL for document:', documentId);

      // Step 2: Upload directly to Firebase Storage
      onProgress?.(10); // 10% - Starting direct upload
      
      await this.uploadToFirebaseStorage(file, uploadUrl, onProgress, signal);
      console.log('✅ File uploaded to Firebase Storage');

      // Step 3: Confirm upload and trigger processing
      onProgress?.(95); // 95% - Confirming upload
      
      console.log('🔄 Making confirm-upload request for document:', documentId);
      console.log('🔄 Confirm-upload URL:', `/documents/${documentId}/confirm-upload`);
      
      // Add retry logic for confirm-upload (based on Google Cloud best practices)
      let confirmResponse;
      let lastError;
      
      for (let attempt = 1; attempt <= 3; attempt++) {
        try {
          console.log(`🔄 Confirm-upload attempt ${attempt}/3`);
          confirmResponse = await apiClient.post(`/documents/${documentId}/confirm-upload`, {}, { 
            signal,
            timeout: 60000 // 60 second timeout for confirm-upload
          });
          console.log('✅ Confirm-upload response received:', confirmResponse.status);
          console.log('✅ Confirm-upload response data:', confirmResponse.data);
          break; // Success, exit retry loop
        } catch (error: any) {
          lastError = error;
          console.log(`❌ Confirm-upload attempt ${attempt} failed:`, error.message);
          
          if (attempt < 3) {
            // Wait before retry (exponential backoff)
            const delay = Math.pow(2, attempt) * 1000; // 2s, 4s
            console.log(`⏳ Waiting ${delay}ms before retry...`);
            await new Promise(resolve => setTimeout(resolve, delay));
          }
        }
      }
      
      if (!confirmResponse) {
        throw lastError || new Error('Confirm-upload failed after 3 attempts');
      }
      
      onProgress?.(100); // 100% - Complete
      console.log('✅ Upload confirmed and processing started');

      return {
        id: documentId,
        ...confirmResponse.data.document
      };

    } catch (error: any) {
      console.error('❌ Firebase Storage upload failed:', error);
      
      // Handle specific error cases
      if (error.name === 'AbortError') {
        throw new Error('Upload was cancelled.');
      }
      
      // Handle network timeouts
      if (error.code === 'ECONNABORTED' || error.message?.includes('timeout')) {
        throw new Error('Request timed out. Please check your connection and try again.');
      }
      
      // Handle network errors
      if (error.code === 'ERR_NETWORK' || error.message?.includes('Network Error')) {
        throw new Error('Network error. Please check your connection and try again.');
      }
      
      if (error.response?.status === 401) {
        throw new Error('Authentication required. Please log in again.');
      }
      
      if (error.response?.status === 400) {
        throw new Error(error.response?.data?.error || 'Invalid request');
      }
      
      if (error.response?.status >= 500) {
        throw new Error('Server error. Please try again later.');
      }
      
      // Generic error fallback
      throw new Error(error.response?.data?.error || error.message || 'Upload failed');
    }
  }

  /**
   * Upload file directly to Firebase Storage using signed URL
   */
  private async uploadToFirebaseStorage(
    file: File,
    uploadUrl: string,
    onProgress?: (progress: number) => void,
    signal?: AbortSignal
  ): Promise<void> {
    return new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest();
      
      // Handle upload progress
      xhr.upload.addEventListener('progress', (event) => {
        if (event.lengthComputable && onProgress) {
          // Map Firebase Storage upload to 10%-90% of overall progress
          const uploadProgress = Math.round((event.loaded / event.total) * 80) + 10;
          onProgress(uploadProgress);
        }
      });

      // Handle completion
      xhr.addEventListener('load', () => {
        if (xhr.status >= 200 && xhr.status < 300) {
          resolve();
        } else {
          reject(new Error(`Firebase Storage upload failed: ${xhr.status} ${xhr.statusText}`));
        }
      });

      // Handle errors
      xhr.addEventListener('error', () => {
        reject(new Error('Firebase Storage upload failed: Network error'));
      });

      // Handle abort
      if (signal) {
        signal.addEventListener('abort', () => {
          xhr.abort();
          reject(new Error('Upload was cancelled'));
        });
      }

      // Start upload
      xhr.open('PUT', uploadUrl);
      xhr.setRequestHeader('Content-Type', file.type);
      xhr.send(file);
    });
  }

  /**
   * Legacy multipart upload method (kept for compatibility)
   */
  async uploadDocumentLegacy(
    file: File, 
    onProgress?: (progress: number) => void, 
    signal?: AbortSignal
  ): Promise<Document> {
    try {
      // Check authentication before upload
      const token = await authService.getToken();
      if (!token) {
        throw new Error('Authentication required. Please log in to upload documents.');
      }

      console.log('📤 Starting legacy multipart upload...');
      console.log('📤 File:', file.name, 'Size:', file.size, 'Type:', file.type);
      console.log('📤 Token available:', !!token);

      const formData = new FormData();
      formData.append('document', file);
      
      // Always use optimized agentic RAG processing - no strategy selection needed
      formData.append('processingStrategy', 'optimized_agentic_rag');

      const response = await apiClient.post('/documents/upload', formData, {
        headers: {
          'Content-Type': 'multipart/form-data',
        },
        signal, // Add abort signal support
        onUploadProgress: (progressEvent) => {
          if (onProgress && progressEvent.total) {
            const progress = Math.round((progressEvent.loaded * 100) / progressEvent.total);
            onProgress(progress);
          }
        },
      });

      console.log('✅ Legacy document upload successful:', response.data);
      return response.data;
    } catch (error: any) {
      console.error('❌ Legacy document upload failed:', error);
      
      // Provide more specific error messages
      if (error.response?.status === 401) {
        if (error.response?.data?.error === 'No valid authorization header') {
          throw new Error('Authentication required. Please log in to upload documents.');
        } else if (error.response?.data?.error === 'Token expired') {
          throw new Error('Your session has expired. Please log in again.');
        } else if (error.response?.data?.error === 'Invalid token') {
          throw new Error('Authentication failed. Please log in again.');
        } else {
          throw new Error('Authentication error. Please log in again.');
        }
      } else if (error.response?.status === 400) {
        if (error.response?.data?.error === 'No file uploaded') {
          throw new Error('No file was selected for upload.');
        } else if (error.response?.data?.error === 'File too large') {
          throw new Error('File is too large. Please select a smaller file.');
        } else if (error.response?.data?.error === 'File type not allowed') {
          throw new Error('File type not supported. Please upload a PDF or text file.');
        } else {
          throw new Error(`Upload failed: ${error.response?.data?.error || 'Bad request'}`);
        }
      } else if (error.response?.status === 413) {
        throw new Error('File is too large. Please select a smaller file.');
      } else if (error.response?.status >= 500) {
        throw new Error('Server error. Please try again later.');
      } else if (error.code === 'ERR_NETWORK') {
        throw new Error('Network error. Please check your connection and try again.');
      } else if (error.name === 'AbortError') {
        throw new Error('Upload was cancelled.');
      }
      
      // Handle GCS-specific errors
      if (error.response?.data?.type === 'storage_error' || 
          error.message?.includes('GCS') || 
          error.message?.includes('storage.googleapis.com')) {
        throw GCSErrorHandler.createGCSError(error, 'upload');
      }
      
      // Generic error fallback
      throw new Error(error.response?.data?.error || error.message || 'Upload failed');
    }
  }

  /**
   * Get all documents for the current user
   */
  async getDocuments(): Promise<Document[]> {
    const response = await apiClient.get('/documents');
    return response.data;
  }

  /**
   * Get a specific document by ID
   */
  async getDocument(documentId: string): Promise<Document> {
    const response = await apiClient.get(`/documents/${documentId}`);
    return response.data;
  }

  /**
   * Get document processing status
   */
  async getDocumentStatus(documentId: string): Promise<{ status: string; progress: number; message?: string }> {
    const response = await apiClient.get(`/documents/${documentId}/progress`);
    return response.data;
  }

  /**
   * Download a processed document
   */
  async downloadDocument(documentId: string): Promise<Blob> {
    try {
      const response = await apiClient.get(`/documents/${documentId}/download`, {
        responseType: 'blob',
      });
      return response.data;
    } catch (error: any) {
      // Handle GCS-specific errors
      if (error.response?.data?.type === 'storage_error' || 
          error.message?.includes('GCS') || 
          error.message?.includes('storage.googleapis.com')) {
        throw GCSErrorHandler.createGCSError(error, 'download');
      }
      throw error;
    }
  }

  /**
   * Delete a document
   */
  async deleteDocument(documentId: string): Promise<void> {
    await apiClient.delete(`/documents/${documentId}`);
  }

  /**
   * Retry processing for a failed document
   */
  async retryProcessing(documentId: string): Promise<Document> {
    const response = await apiClient.post(`/documents/${documentId}/retry`);
    return response.data;
  }

  /**
   * Save CIM review data
   */
  async saveCIMReview(documentId: string, reviewData: CIMReviewData): Promise<void> {
    await apiClient.post(`/documents/${documentId}/review`, reviewData);
  }

  /**
   * Get CIM review data for a document
   */
  async getCIMReview(documentId: string): Promise<CIMReviewData> {
    const response = await apiClient.get(`/documents/${documentId}/review`);
    return response.data;
  }

  /**
   * Export CIM review as PDF
   */
  async exportCIMReview(documentId: string): Promise<Blob> {
    const response = await apiClient.get(`/documents/${documentId}/export`, {
      responseType: 'blob',
    });
    return response.data;
  }

  /**
   * Get document analytics and insights
   */
  async getDocumentAnalytics(documentId: string): Promise<any> {
    const response = await apiClient.get(`/documents/${documentId}/analytics`);
    return response.data;
  }

  /**
   * Get global analytics data
   */
  async getAnalytics(days: number = 30): Promise<any> {
    const response = await apiClient.get('/documents/analytics', {
      params: { days }
    });
    return response.data;
  }

  /**
   * Get processing statistics
   */
  async getProcessingStats(): Promise<any> {
    const response = await apiClient.get('/documents/processing-stats');
    return response.data;
  }

  /**
   * Get agentic RAG sessions for a document
   */
  async getAgenticRAGSessions(documentId: string): Promise<any> {
    const response = await apiClient.get(`/documents/${documentId}/agentic-rag-sessions`);
    return response.data;
  }

  /**
   * Get detailed agentic RAG session information
   */
  async getAgenticRAGSessionDetails(sessionId: string): Promise<any> {
    const response = await apiClient.get(`/documents/agentic-rag-sessions/${sessionId}`);
    return response.data;
  }

  /**
   * Get agentic RAG health status
   */
  async getAgenticRAGHealth(): Promise<any> {
    const response = await apiClient.get('/health/agentic-rag');
    return response.data;
  }

  /**
   * Get agentic RAG performance metrics
   */
  async getAgenticRAGMetrics(): Promise<any> {
    const response = await apiClient.get('/health/agentic-rag/metrics');
    return response.data;
  }

  /**
   * Search documents
   */
  async searchDocuments(query: string): Promise<Document[]> {
    const response = await apiClient.get('/documents/search', {
      params: { q: query },
    });
    return response.data;
  }

  /**
   * Get processing queue status
   */
  async getQueueStatus(): Promise<{ pending: number; processing: number; completed: number; failed: number }> {
    const response = await apiClient.get('/documents/queue/status');
    return response.data;
  }

  /**
   * Subscribe to document processing updates via WebSocket
   */
  subscribeToUpdates(documentId: string, callback: (update: UploadProgress) => void): () => void {
    // In a real implementation, this would use WebSocket or Server-Sent Events
    // For now, we'll simulate with polling
    const interval = setInterval(async () => {
      try {
        const status = await this.getDocumentStatus(documentId);
        callback({
          documentId,
          progress: status.progress,
          status: status.status as any,
          message: status.message,
        });
      } catch (error) {
        console.error('Error fetching document status:', error);
      }
    }, 2000);

    return () => clearInterval(interval);
  }

  /**
   * Validate file before upload
   */
  validateFile(file: File): { isValid: boolean; error?: string } {
    const maxSize = 50 * 1024 * 1024; // 50MB
    const allowedTypes = [
      'application/pdf',
      'application/msword',
      'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    ];

    if (file.size > maxSize) {
      return { isValid: false, error: 'File size exceeds 50MB limit' };
    }

    if (!allowedTypes.includes(file.type)) {
      return { isValid: false, error: 'File type not supported. Please upload PDF, DOC, or DOCX files.' };
    }

    return { isValid: true };
  }

  /**
   * Generate a download URL for a document
   * Handles both GCS direct URLs and API proxy URLs
   */
  getDownloadUrl(documentId: string, document?: Document): string {
    // If document has a GCS URL, use it directly for better performance
    if (document?.gcs_url && document.storage_type === 'gcs') {
      return document.gcs_url;
    }
    
    // Fallback to API proxy URL
    return `${API_BASE_URL}/documents/${documentId}/download`;
  }

  /**
   * Check if a document is stored in GCS
   */
  isGCSDocument(document: Document): boolean {
    return document.storage_type === 'gcs' || !!document.gcs_path || !!document.gcs_url;
  }

  /**
   * Get GCS-specific file info
   */
  getGCSFileInfo(document: Document): { gcsPath?: string; gcsUrl?: string; storageType: string } {
    return {
      gcsPath: document.gcs_path,
      gcsUrl: document.gcs_url,
      storageType: document.storage_type || 'unknown'
    };
  }

  /**
   * Format file size for display
   */
  formatFileSize(bytes: number): string {
    if (bytes === 0) return '0 Bytes';
    const k = 1024;
    const sizes = ['Bytes', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
  }

  /**
   * Format date for display
   */
  formatDate(dateString: string): string {
    return new Date(dateString).toLocaleDateString('en-US', {
      year: 'numeric',
      month: 'short',
      day: 'numeric',
      hour: '2-digit',
      minute: '2-digit',
    });
  }
}

export const documentService = new DocumentService(); 