const { v4: uuidv4 } = require('uuid');
const database = require('../config/database');

class DiffStorageModel {
  constructor() {
    this.db = database;
  }

  async createDiffContent(diffData) {
    const {
      commit_id,
      file_change_id,
      diff_header,
      diff_size_bytes,
      storage_type = 'external',
      external_storage_path,
      external_storage_provider = 'local',
      file_path,
      change_type,
      processing_status = 'pending'
    } = diffData;

    const query = `
      INSERT INTO diff_contents (
        id, commit_id, file_change_id, diff_header, diff_size_bytes,
        storage_type, external_storage_path, external_storage_provider,
        file_path, change_type, processing_status, created_at, updated_at
      ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, NOW(), NOW())
      RETURNING *
    `;

    const values = [
      uuidv4(),
      commit_id,
      file_change_id,
      diff_header,
      diff_size_bytes,
      storage_type,
      external_storage_path,
      external_storage_provider,
      file_path,
      change_type,
      processing_status
    ];

    const result = await this.db.query(query, values);
    return result.rows[0];
  }

  async updateProcessingStatus(diff_id, status, error_message = null) {
    const query = `
      UPDATE diff_contents 
      SET processing_status = $2, processing_error = $3, updated_at = NOW()
      WHERE id = $1
      RETURNING *
    `;

    const result = await this.db.query(query, [diff_id, status, error_message]);
    return result.rows[0];
  }

  async getDiffsByCommit(commit_id) {
    const query = `
      SELECT * FROM diff_contents 
      WHERE commit_id = $1 
      ORDER BY file_path
    `;
    
    const result = await this.db.query(query, [commit_id]);
    return result.rows;
  }

  async getDiffsByRepository(repository_id, limit = 50, offset = 0) {
    const query = `
      SELECT dc.*, rcd.commit_sha, rcd.committed_at
      FROM diff_contents dc
      JOIN repository_commit_details rcd ON dc.commit_id = rcd.id
      WHERE rcd.repository_id = $1
      ORDER BY rcd.committed_at DESC, dc.file_path
      LIMIT $2 OFFSET $3
    `;
    
    const result = await this.db.query(query, [repository_id, limit, offset]);
    return result.rows;
  }

  async getDiffById(diff_id) {
    const query = `SELECT * FROM diff_contents WHERE id = $1`;
    const result = await this.db.query(query, [diff_id]);
    return result.rows[0];
  }

  // Diff Processing Queue methods
  async addToProcessingQueue(queueData) {
    const {
      commit_id,
      repository_id,
      queue_status = 'pending',
      priority = 0,
      from_sha,
      to_sha,
      repo_local_path
    } = queueData;

    const query = `
      INSERT INTO diff_processing_queue (
        id, commit_id, repository_id, queue_status, priority,
        from_sha, to_sha, repo_local_path, created_at, updated_at
      ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW(), NOW())
      RETURNING *
    `;

    const values = [
      uuidv4(),
      commit_id,
      repository_id,
      queue_status,
      priority,
      from_sha,
      to_sha,
      repo_local_path
    ];

    const result = await this.db.query(query, values);
    return result.rows[0];
  }

  async getNextQueueItem() {
    const query = `
      SELECT * FROM diff_processing_queue 
      WHERE queue_status = 'pending' 
      ORDER BY priority DESC, created_at ASC 
      LIMIT 1
    `;
    
    const result = await this.db.query(query);
    return result.rows[0];
  }

  async updateQueueStatus(queue_id, status, error_message = null) {
    const query = `
      UPDATE diff_processing_queue 
      SET queue_status = $2, error_message = $3, 
          processed_at = CASE WHEN $2 IN ('completed', 'failed') THEN NOW() ELSE processed_at END,
          updated_at = NOW()
      WHERE id = $1
      RETURNING *
    `;

    const result = await this.db.query(query, [queue_id, status, error_message]);
    return result.rows[0];
  }

  async incrementRetryCount(queue_id) {
    const query = `
      UPDATE diff_processing_queue 
      SET retry_count = retry_count + 1, updated_at = NOW()
      WHERE id = $1
      RETURNING *
    `;

    const result = await this.db.query(query, [queue_id]);
    return result.rows[0];
  }

  // Statistics methods
  async createDiffStatistics(statsData) {
    const {
      repository_id,
      period_start,
      period_end,
      total_commits = 0,
      total_files_changed = 0,
      total_diffs_processed = 0,
      total_diff_size_bytes = 0,
      avg_diff_size_bytes = 0,
      max_diff_size_bytes = 0,
      diffs_stored_external = 0,
      avg_processing_time_ms = 0,
      failed_processing_count = 0
    } = statsData;

    const query = `
      INSERT INTO diff_statistics (
        id, repository_id, period_start, period_end, total_commits,
        total_files_changed, total_diffs_processed, total_diff_size_bytes,
        avg_diff_size_bytes, max_diff_size_bytes, diffs_stored_external,
        avg_processing_time_ms, failed_processing_count, created_at
      ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, NOW())
      RETURNING *
    `;

    const values = [
      uuidv4(),
      repository_id,
      period_start,
      period_end,
      total_commits,
      total_files_changed,
      total_diffs_processed,
      total_diff_size_bytes,
      avg_diff_size_bytes,
      max_diff_size_bytes,
      diffs_stored_external,
      avg_processing_time_ms,
      failed_processing_count
    ];

    const result = await this.db.query(query, values);
    return result.rows[0];
  }

  async getRepositoryDiffStats(repository_id, days_back = 30) {
    const query = `SELECT * FROM get_repository_diff_stats($1, $2)`;
    const result = await this.db.query(query, [repository_id, days_back]);
    return result.rows[0];
  }

  async cleanupOldQueueEntries(days_back = 7) {
    const query = `SELECT cleanup_old_diff_queue_entries($1)`;
    const result = await this.db.query(query, [days_back]);
    return result.rows[0].cleanup_old_diff_queue_entries;
  }
}

module.exports = DiffStorageModel;
