import { getSupabaseServiceClient } from '../config/supabase';
import { Document, CreateDocumentInput, ProcessingStatus } from './types';
import logger from '../utils/logger';

export class DocumentModel {
  /**
   * Create a new document
   */
  static async create(documentData: CreateDocumentInput): Promise<Document> {
    const { user_id, original_file_name, file_path, file_size, status = 'uploaded' } = documentData;
    
    const supabase = getSupabaseServiceClient();
    
    try {
      const { data, error } = await supabase
        .from('documents')
        .insert({
          user_id,
          original_file_name,
          file_path,
          file_size,
          status
        })
        .select()
        .single();
      
      if (error) {
        logger.error('Error creating document:', error);
        throw error;
      }
      
      logger.info(`Created document: ${original_file_name} for user: ${user_id} with status: ${status}`);
      return data;
    } catch (error) {
      logger.error('Error creating document:', error);
      throw error;
    }
  }

  /**
   * Find document by ID
   */
  static async findById(id: string): Promise<Document | null> {
    const supabase = getSupabaseServiceClient();
    
    try {
      const { data, error } = await supabase
        .from('documents')
        .select('*')
        .eq('id', id)
        .single();
      
      if (error) {
        if (error.code === 'PGRST116') {
          return null; // No rows returned
        }
        logger.error('Error finding document by ID:', error);
        throw error;
      }
      
      return data;
    } catch (error) {
      logger.error('Error finding document by ID:', error);
      throw error;
    }
  }

  /**
   * Find document by ID with user information
   */
  static async findByIdWithUser(id: string): Promise<(Document & { user_name: string, user_email: string }) | null> {
    const supabase = getSupabaseServiceClient();
    
    try {
      const { data, error } = await supabase
        .from('documents')
        .select(`
          *,
          users!inner(name, email)
        `)
        .eq('id', id)
        .single();
      
      if (error) {
        if (error.code === 'PGRST116') {
          return null; // No rows returned
        }
        logger.error('Error finding document with user:', error);
        throw error;
      }
      
      return {
        ...data,
        user_name: data.users?.name,
        user_email: data.users?.email
      };
    } catch (error) {
      logger.error('Error finding document with user:', error);
      throw error;
    }
  }

  /**
   * Get documents by user ID
   */
  static async findByUserId(userId: string, limit = 50, offset = 0): Promise<Document[]> {
    const supabase = getSupabaseServiceClient();
    
    try {
      const { data, error } = await supabase
        .from('documents')
        .select('*')
        .eq('user_id', userId)
        .order('created_at', { ascending: false })
        .range(offset, offset + limit - 1);
      
      if (error) {
        logger.error('Error finding documents by user ID:', error);
        throw error;
      }
      
      return data || [];
    } catch (error) {
      logger.error('Error finding documents by user ID:', error);
      throw error;
    }
  }

  /**
   * Get all documents (for admin)
   */
  static async findAll(limit = 100, offset = 0): Promise<(Document & { user_name: string, user_email: string })[]> {
    const supabase = getSupabaseServiceClient();
    
    try {
      const { data, error } = await supabase
        .from('documents')
        .select(`
          *,
          users!inner(name, email)
        `)
        .order('created_at', { ascending: false })
        .range(offset, offset + limit - 1);
      
      if (error) {
        logger.error('Error finding all documents:', error);
        throw error;
      }
      
      return (data || []).map(doc => ({
        ...doc,
        user_name: doc.users?.name,
        user_email: doc.users?.email
      }));
    } catch (error) {
      logger.error('Error finding all documents:', error);
      throw error;
    }
  }

  /**
   * Update document by ID
   */
  static async updateById(id: string, updateData: Partial<Document>): Promise<Document | null> {
    const supabase = getSupabaseServiceClient();
    
    try {
      const { data, error } = await supabase
        .from('documents')
        .update({
          ...updateData,
          updated_at: new Date().toISOString()
        })
        .eq('id', id)
        .select()
        .single();
      
      if (error) {
        if (error.code === 'PGRST116') {
          return null; // No rows returned
        }
        logger.error('Error updating document by ID:', error);
        throw error;
      }
      
      return data;
    } catch (error) {
      logger.error('Error updating document by ID:', error);
      throw error;
    }
  }

  /**
   * Update document status
   */
  static async updateStatus(id: string, status: ProcessingStatus): Promise<Document | null> {
    return this.updateById(id, { status });
  }

  /**
   * Update extracted text
   */
  static async updateExtractedText(id: string, extractedText: string): Promise<Document | null> {
    return this.updateById(id, { extracted_text: extractedText });
  }

  /**
   * Update generated summary
   */
  static async updateGeneratedSummary(id: string, summary: string): Promise<Document | null> {
    return this.updateById(id, { 
      generated_summary: summary,
      processing_completed_at: new Date()
    });
  }

  /**
   * Update error message
   */
  static async updateErrorMessage(id: string, errorMessage: string): Promise<Document | null> {
    return this.updateById(id, { error_message: errorMessage });
  }

  /**
   * Update analysis results
   */
  static async updateAnalysisResults(id: string, analysisData: any): Promise<Document | null> {
    return this.updateById(id, { analysis_data: analysisData });
  }

  /**
   * Delete document
   */
  static async delete(id: string): Promise<boolean> {
    const supabase = getSupabaseServiceClient();
    
    try {
      const { error } = await supabase
        .from('documents')
        .delete()
        .eq('id', id);
      
      if (error) {
        logger.error('Error deleting document:', error);
        throw error;
      }
      
      return true;
    } catch (error) {
      logger.error('Error deleting document:', error);
      throw error;
    }
  }

  /**
   * Count documents by user
   */
  static async countByUser(userId: string): Promise<number> {
    const supabase = getSupabaseServiceClient();
    
    try {
      const { count, error } = await supabase
        .from('documents')
        .select('*', { count: 'exact', head: true })
        .eq('user_id', userId);
      
      if (error) {
        logger.error('Error counting documents by user:', error);
        throw error;
      }
      
      return count || 0;
    } catch (error) {
      logger.error('Error counting documents by user:', error);
      throw error;
    }
  }

  /**
   * Count all documents
   */
  static async count(): Promise<number> {
    const supabase = getSupabaseServiceClient();
    
    try {
      const { count, error } = await supabase
        .from('documents')
        .select('*', { count: 'exact', head: true });
      
      if (error) {
        logger.error('Error counting documents:', error);
        throw error;
      }
      
      return count || 0;
    } catch (error) {
      logger.error('Error counting documents:', error);
      throw error;
    }
  }

  /**
   * Find documents by status
   */
  static async findByStatus(status: ProcessingStatus, limit = 50, offset = 0): Promise<Document[]> {
    const supabase = getSupabaseServiceClient();
    
    try {
      const { data, error } = await supabase
        .from('documents')
        .select('*')
        .eq('status', status)
        .order('created_at', { ascending: false })
        .range(offset, offset + limit - 1);
      
      if (error) {
        logger.error('Error finding documents by status:', error);
        throw error;
      }
      
      return data || [];
    } catch (error) {
      logger.error('Error finding documents by status:', error);
      throw error;
    }
  }

  /**
   * Find documents pending processing
   */
  static async findPendingProcessing(limit = 10): Promise<Document[]> {
    const supabase = getSupabaseServiceClient();
    
    try {
      const { data, error } = await supabase
        .from('documents')
        .select('*')
        .in('status', ['uploaded', 'extracting_text', 'processing'])
        .order('created_at', { ascending: true })
        .limit(limit);
      
      if (error) {
        logger.error('Error finding pending processing documents:', error);
        throw error;
      }
      
      return data || [];
    } catch (error) {
      logger.error('Error finding pending processing documents:', error);
      throw error;
    }
  }
} 