// routes/diff-viewer.routes.js
const express = require('express');
const router = express.Router();
const DiffProcessingService = require('../services/diff-processing.service');
const database = require('../config/database');

const diffService = new DiffProcessingService();

// Get all repositories
router.get('/repositories', async (req, res) => {
  try {
    const { limit = 50, offset = 0 } = req.query;

    const query = `
      SELECT 
        ar.id,
        ar.repository_name,
        ar.owner_name,
        ar.sync_status,
        ar.created_at,
        ar.updated_at,
        ar.last_synced_at
      FROM all_repositories ar
      ORDER BY ar.created_at DESC
      LIMIT $1 OFFSET $2
    `;

    const result = await database.query(query, [limit, offset]);
    
    res.json({
      success: true,
      data: {
        repositories: result.rows,
        pagination: {
          limit: parseInt(limit),
          offset: parseInt(offset),
          total: result.rows.length
        }
      }
    });
  } catch (error) {
    console.error('Error fetching repositories:', error);
    res.status(500).json({
      success: false,
      message: 'Failed to fetch repositories',
      error: error.message
    });
  }
});

// Get all commits for a repository with diff metadata
router.get('/repositories/:repositoryId/commits', async (req, res) => {
  try {
    const { repositoryId } = req.params;
    const { limit = 20, offset = 0, branch = null } = req.query;

    const query = `
      SELECT 
        rcd.id,
        rcd.commit_sha,
        rcd.author_name,
        rcd.author_email,
        rcd.message,
        rcd.url,
        rcd.committed_at,
        COUNT(rcf.id) as files_changed,
        COUNT(dc.id) as diffs_processed,
        COALESCE(SUM(dc.diff_size_bytes), 0) as total_diff_size
      FROM repository_commit_details rcd
      LEFT JOIN repository_commit_files rcf ON rcd.id = rcf.commit_id
      LEFT JOIN diff_contents dc ON rcd.id = dc.commit_id
      WHERE rcd.repository_id = $1
      GROUP BY rcd.id, rcd.commit_sha, rcd.author_name, rcd.author_email, 
               rcd.message, rcd.url, rcd.committed_at
      ORDER BY rcd.committed_at DESC
      LIMIT $2 OFFSET $3
    `;

    const result = await database.query(query, [repositoryId, limit, offset]);
    
    res.json({
      success: true,
      data: {
        commits: result.rows,
        pagination: {
          limit: parseInt(limit),
          offset: parseInt(offset),
          total: result.rows.length
        }
      }
    });
  } catch (error) {
    console.error('Error fetching commits:', error);
    res.status(500).json({
      success: false,
      message: 'Failed to fetch commits',
      error: error.message
    });
  }
});

// Get diff details for a specific commit
router.get('/commits/:commitId/diffs', async (req, res) => {
  try {
    const { commitId } = req.params;
    const { view = 'side-by-side' } = req.query;

    // Get commit metadata
    const commitQuery = `
      SELECT 
        rcd.id,
        rcd.commit_sha,
        rcd.author_name,
        rcd.author_email,
        rcd.message,
        rcd.url,
        rcd.committed_at,
        ar.repository_name,
        ar.owner_name
      FROM repository_commit_details rcd
      JOIN all_repositories ar ON rcd.repository_id = ar.id
      WHERE rcd.id = $1
    `;

    const commitResult = await database.query(commitQuery, [commitId]);
    
    if (commitResult.rows.length === 0) {
      return res.status(404).json({
        success: false,
        message: 'Commit not found'
      });
    }

    const commit = commitResult.rows[0];

    // Get file changes with diff metadata
    const filesQuery = `
      SELECT 
        rcf.id as file_change_id,
        rcf.file_path,
        rcf.change_type,
        dc.id as diff_content_id,
        dc.diff_header,
        dc.diff_size_bytes,
        dc.storage_type,
        dc.external_storage_path,
        dc.processing_status
      FROM repository_commit_files rcf
      LEFT JOIN diff_contents dc ON rcf.id = dc.file_change_id
      WHERE rcf.commit_id = $1
      ORDER BY rcf.file_path
    `;

    const filesResult = await database.query(filesQuery, [commitId]);
    
    // Get actual diff content for each file
    const filesWithDiff = await Promise.all(
      filesResult.rows.map(async (file) => {
        let diffContent = null;
        
        if (file.diff_content_id && file.storage_type === 'external') {
          try {
            diffContent = await diffService.getDiffContent(file.diff_content_id);
          } catch (error) {
            console.warn(`Failed to load diff content for file ${file.file_path}:`, error.message);
          }
        }
        
        return {
          ...file,
          diff_content: diffContent
        };
      })
    );

    // Calculate statistics by parsing diff content
    let totalAdditions = 0;
    let totalDeletions = 0;
    
    filesWithDiff.forEach(file => {
      if (file.diff_content) {
        const lines = file.diff_content.split('\n');
        lines.forEach(line => {
          if (line.startsWith('+') && !line.startsWith('+++')) {
            totalAdditions++;
          } else if (line.startsWith('-') && !line.startsWith('---')) {
            totalDeletions++;
          }
        });
      }
    });

    const stats = {
      total_files: filesWithDiff.length,
      total_additions: totalAdditions,
      total_deletions: totalDeletions,
      total_size_bytes: filesWithDiff.reduce((sum, file) => sum + (file.diff_size_bytes || 0), 0),
      files_by_type: {
        added: filesWithDiff.filter(f => f.change_type === 'added').length,
        modified: filesWithDiff.filter(f => f.change_type === 'modified').length,
        deleted: filesWithDiff.filter(f => f.change_type === 'deleted').length,
        renamed: filesWithDiff.filter(f => f.change_type === 'renamed').length
      }
    };

    res.json({
      success: true,
      data: {
        commit,
        files: filesWithDiff,
        statistics: stats,
        view_preferences: {
          default_view: view,
          available_views: ['side-by-side', 'unified']
        }
      }
    });
  } catch (error) {
    console.error('Error fetching commit diffs:', error);
    res.status(500).json({
      success: false,
      message: 'Failed to fetch commit diffs',
      error: error.message
    });
  }
});

// Get specific file diff content
router.get('/files/:fileChangeId/diff', async (req, res) => {
  try {
    const { fileChangeId } = req.params;
    const { format = 'raw' } = req.query;

    const query = `
      SELECT 
        rcf.file_path,
        rcf.change_type,
        dc.diff_header,
        dc.diff_size_bytes,
        dc.storage_type,
        dc.external_storage_path,
        dc.processing_status
      FROM repository_commit_files rcf
      LEFT JOIN diff_contents dc ON rcf.id = dc.file_change_id
      WHERE rcf.id = $1
    `;

    const result = await database.query(query, [fileChangeId]);
    
    if (result.rows.length === 0) {
      return res.status(404).json({
        success: false,
        message: 'File diff not found'
      });
    }

    const fileDiff = result.rows[0];
    let diffContent = null;

    if (fileDiff.diff_content_id && fileDiff.storage_type === 'external') {
      try {
        diffContent = await diffService.getDiffContent(fileDiff.diff_content_id);
      } catch (error) {
        console.warn(`Failed to load diff content:`, error.message);
      }
    }

    if (format === 'parsed') {
      // Parse diff content into structured format
      const parsedDiff = diffService.parseDiffContent(diffContent || '');
      return res.json({
        success: true,
        data: {
          file_path: fileDiff.file_path,
          change_type: fileDiff.change_type,
          diff_header: fileDiff.diff_header,
          diff_size_bytes: fileDiff.diff_size_bytes,
          processing_status: fileDiff.processing_status,
          parsed_diff: parsedDiff
        }
      });
    }

    res.json({
      success: true,
      data: {
        file_path: fileDiff.file_path,
        change_type: fileDiff.change_type,
        diff_header: fileDiff.diff_header,
        diff_content: diffContent,
        diff_size_bytes: fileDiff.diff_size_bytes,
        processing_status: fileDiff.processing_status
      }
    });
  } catch (error) {
    console.error('Error fetching file diff:', error);
    res.status(500).json({
      success: false,
      message: 'Failed to fetch file diff',
      error: error.message
    });
  }
});

// Get repository diff statistics
router.get('/repositories/:repositoryId/stats', async (req, res) => {
  try {
    const { repositoryId } = req.params;
    const { days = 30 } = req.query;

    const statsQuery = `
      SELECT 
        COUNT(DISTINCT rcd.id) as total_commits,
        COUNT(DISTINCT rcf.id) as total_files_changed,
        COUNT(DISTINCT dc.id) as total_diffs_processed,
        COALESCE(SUM(dc.diff_size_bytes), 0) as total_diff_size,
        COALESCE(AVG(dc.diff_size_bytes), 0) as avg_diff_size,
        COALESCE(MAX(dc.diff_size_bytes), 0) as max_diff_size,
        COUNT(*) FILTER (WHERE dc.storage_type = 'external') as external_storage_count
      FROM repository_commit_details rcd
      LEFT JOIN repository_commit_files rcf ON rcd.id = rcf.commit_id
      LEFT JOIN diff_contents dc ON rcd.id = dc.commit_id
      WHERE rcd.repository_id = $1 
        AND rcd.committed_at >= NOW() - INTERVAL '${parseInt(days)} days'
    `;

    const result = await database.query(statsQuery, [repositoryId]);
    
    res.json({
      success: true,
      data: {
        statistics: result.rows[0],
        period_days: parseInt(days)
      }
    });
  } catch (error) {
    console.error('Error fetching repository stats:', error);
    res.status(500).json({
      success: false,
      message: 'Failed to fetch repository statistics',
      error: error.message
    });
  }
});

// Search diffs across repository
router.get('/repositories/:repositoryId/search', async (req, res) => {
  try {
    const { repositoryId } = req.params;
    const { q: searchQuery, limit = 20, offset = 0 } = req.query;

    if (!searchQuery) {
      return res.status(400).json({
        success: false,
        message: 'Search query is required'
      });
    }

    const searchQuerySQL = `
      SELECT 
        rcd.id as commit_id,
        rcd.commit_sha,
        rcd.author_name,
        rcd.message,
        rcd.committed_at,
        rcf.file_path,
        rcf.change_type,
        dc.diff_size_bytes
      FROM repository_commit_details rcd
      JOIN repository_commit_files rcf ON rcd.id = rcf.commit_id
      LEFT JOIN diff_contents dc ON rcf.id = dc.file_change_id
      WHERE rcd.repository_id = $1
        AND (
          rcd.message ILIKE $2 
          OR rcf.file_path ILIKE $2
          OR rcd.author_name ILIKE $2
        )
      ORDER BY rcd.committed_at DESC
      LIMIT $3 OFFSET $4
    `;

    const searchPattern = `%${searchQuery}%`;
    const result = await database.query(searchQuerySQL, [repositoryId, searchPattern, limit, offset]);
    
    res.json({
      success: true,
      data: {
        results: result.rows,
        query: searchQuery,
        pagination: {
          limit: parseInt(limit),
          offset: parseInt(offset),
          total: result.rows.length
        }
      }
    });
  } catch (error) {
    console.error('Error searching diffs:', error);
    res.status(500).json({
      success: false,
      message: 'Failed to search diffs',
      error: error.message
    });
  }
});

module.exports = router;
