// Updated routes/github-integration.js
const express = require('express');
const router = express.Router();
const GitHubIntegrationService = require('../services/github-integration.service');
const GitHubOAuthService = require('../services/github-oauth');
const FileStorageService = require('../services/file-storage.service');
const database = require('../config/database');
const fs = require('fs');
const path = require('path');

const githubService = new GitHubIntegrationService();
const oauthService = new GitHubOAuthService();
const fileStorageService = new FileStorageService();

// Attach GitHub repository to template
router.post('/attach-repository', async (req, res) => {
  try {
    const { template_id, repository_url, branch_name } = req.body;

    // Validate input
    if (!template_id || !repository_url) {
      return res.status(400).json({
        success: false,
        message: 'Template ID and repository URL are required'
      });
    }

    // Check if template exists
    const templateQuery = 'SELECT * FROM templates WHERE id = $1 AND is_active = true';
    const templateResult = await database.query(templateQuery, [template_id]);
    
    if (templateResult.rows.length === 0) {
      return res.status(404).json({
        success: false,
        message: 'Template not found'
      });
    }

    // Parse GitHub URL
    const { owner, repo, branch } = githubService.parseGitHubUrl(repository_url);

    // Check repository access
    const accessCheck = await githubService.checkRepositoryAccess(owner, repo);
    
    if (!accessCheck.hasAccess) {
      if (accessCheck.requiresAuth) {
        // Check if we have OAuth token
        const tokenRecord = await oauthService.getToken();
        if (!tokenRecord) {
          return res.status(401).json({
            success: false,
            message: 'GitHub authentication required for this repository',
            requires_auth: true,
            auth_url: `/api/github/auth/github`
          });
        }
      }
      
      return res.status(404).json({
        success: false,
        message: accessCheck.error || 'Repository not accessible'
      });
    }

    // Get repository information from GitHub
    const repositoryData = await githubService.fetchRepositoryMetadata(owner, repo);

    // Analyze the codebase
    const codebaseAnalysis = await githubService.analyzeCodebase(owner, repo, branch || branch_name);

    // Store everything in PostgreSQL
    const insertQuery = `
      INSERT INTO github_repositories (
        template_id, repository_url, repository_name, owner_name, 
        branch_name, is_public, metadata, codebase_analysis, sync_status,
        requires_auth
      ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
      RETURNING *
    `;

    const insertValues = [
      template_id,
      repository_url,
      repo,
      owner,
      branch || branch_name || 'main',
      repositoryData.visibility === 'public',
      JSON.stringify(repositoryData),
      JSON.stringify(codebaseAnalysis),
      'synced',
      accessCheck.requiresAuth
    ];

    const insertResult = await database.query(insertQuery, insertValues);
    const repositoryRecord = insertResult.rows[0];

    // Download repository with file storage
    console.log('Downloading repository with storage...');
    const downloadResult = await githubService.downloadRepositoryWithStorage(
      owner, repo, branch || branch_name || 'main', repositoryRecord.id
    );

    if (!downloadResult.success) {
      // If download failed, still return the repository record but mark the storage issue
      console.warn('Repository download failed:', downloadResult.error);
    }

    // Create feature-codebase mappings
    const featureQuery = 'SELECT id FROM template_features WHERE template_id = $1';
    const featureResult = await database.query(featureQuery, [template_id]);
    
    if (featureResult.rows.length > 0) {
      const mappingValues = [];
      const mappingParams = [];
      let paramIndex = 1;
      
      for (const feature of featureResult.rows) {
        mappingValues.push(`(uuid_generate_v4(), $${paramIndex++}, $${paramIndex++}, $${paramIndex++}, $${paramIndex++})`);
        mappingParams.push(
          feature.id,
          repositoryRecord.id,
          '[]', // Empty paths for now
          '{}'  // Empty snippets for now
        );
      }
      
      const mappingQuery = `
        INSERT INTO feature_codebase_mappings (id, feature_id, repository_id, code_paths, code_snippets)
        VALUES ${mappingValues.join(', ')}
      `;
      
      await database.query(mappingQuery, mappingParams);
    }

    // Get storage information
    const storageInfo = await githubService.getRepositoryStorage(repositoryRecord.id);

    res.status(201).json({
      success: true,
      message: 'Repository attached successfully',
      data: {
        repository_id: repositoryRecord.id,
        template_id: repositoryRecord.template_id,
        repository_name: repositoryRecord.repository_name,
        owner_name: repositoryRecord.owner_name,
        branch_name: repositoryRecord.branch_name,
        is_public: repositoryRecord.is_public,
        requires_auth: repositoryRecord.requires_auth,
        metadata: repositoryData,
        codebase_analysis: codebaseAnalysis,
        storage_info: storageInfo,
        download_result: downloadResult
      }
    });

  } catch (error) {
    console.error('Error attaching repository:', error);
    res.status(500).json({
      success: false,
      message: error.message || 'Failed to attach repository'
    });
  }
});

// Get repository information for a template
router.get('/template/:id/repository', async (req, res) => {
  try {
    const { id } = req.params;
    
    const query = `
      SELECT gr.*, rs.local_path, rs.storage_status, rs.total_files_count, 
             rs.total_directories_count, rs.total_size_bytes, rs.download_completed_at
      FROM github_repositories gr
      LEFT JOIN repository_storage rs ON gr.id = rs.repository_id
      WHERE gr.template_id = $1 
      ORDER BY gr.created_at DESC 
      LIMIT 1
    `;
    
    const result = await database.query(query, [id]);
    
    if (result.rows.length === 0) {
      return res.status(404).json({
        success: false,
        message: 'No repository found for this template'
      });
    }
    
    const repository = result.rows[0];

    const parseMaybe = (v) => {
      if (v == null) return {};
      if (typeof v === 'string') {
        try { return JSON.parse(v); } catch { return {}; }
      }
      return v; // already an object from jsonb
    };
    
    res.json({
      success: true,
      data: {
        ...repository,
        metadata: parseMaybe(repository.metadata),
        codebase_analysis: parseMaybe(repository.codebase_analysis)
      }
    });
    
  } catch (error) {
    console.error('Error fetching repository:', error);
    res.status(500).json({
      success: false,
      message: error.message || 'Failed to fetch repository'
    });
  }
});

// Get repository file structure
router.get('/repository/:id/structure', async (req, res) => {
  try {
    const { id } = req.params;
    const { path: directoryPath } = req.query;
    
    // Get repository info
    const repoQuery = 'SELECT * FROM github_repositories WHERE id = $1';
    const repoResult = await database.query(repoQuery, [id]);
    
    if (repoResult.rows.length === 0) {
      return res.status(404).json({
        success: false,
        message: 'Repository not found'
      });
    }

    const structure = await fileStorageService.getRepositoryStructure(id, directoryPath);
    
    res.json({
      success: true,
      data: {
        repository_id: id,
        directory_path: directoryPath || '',
        structure: structure
      }
    });
    
  } catch (error) {
    console.error('Error fetching repository structure:', error);
    res.status(500).json({
      success: false,
      message: error.message || 'Failed to fetch repository structure'
    });
  }
});

// Get files in a directory
router.get('/repository/:id/files', async (req, res) => {
  try {
    const { id } = req.params;
    const { directory_path = '' } = req.query;
    
    // Get repository info
    const repoQuery = 'SELECT * FROM github_repositories WHERE id = $1';
    const repoResult = await database.query(repoQuery, [id]);
    
    if (repoResult.rows.length === 0) {
      return res.status(404).json({
        success: false,
        message: 'Repository not found'
      });
    }

    const files = await fileStorageService.getDirectoryFiles(id, directory_path);
    
    res.json({
      success: true,
      data: {
        repository_id: id,
        directory_path: directory_path,
        files: files
      }
    });
    
  } catch (error) {
    console.error('Error fetching directory files:', error);
    res.status(500).json({
      success: false,
      message: error.message || 'Failed to fetch directory files'
    });
  }
});

// Get file content
router.get('/repository/:id/file-content', async (req, res) => {
  try {
    const { id } = req.params;
    const { file_path } = req.query;
    
    if (!file_path) {
      return res.status(400).json({
        success: false,
        message: 'File path is required'
      });
    }

    const query = `
      SELECT rf.*, rfc.content_text, rfc.content_preview, rfc.language_detected, 
             rfc.line_count, rfc.char_count
      FROM repository_files rf
      LEFT JOIN repository_file_contents rfc ON rf.id = rfc.file_id
      WHERE rf.repository_id = $1 AND rf.relative_path = $2
    `;
    
    const result = await database.query(query, [id, file_path]);
    
    if (result.rows.length === 0) {
      return res.status(404).json({
        success: false,
        message: 'File not found'
      });
    }
    
    const file = result.rows[0];
    
    res.json({
      success: true,
      data: {
        file_info: {
          id: file.id,
          filename: file.filename,
          file_extension: file.file_extension,
          relative_path: file.relative_path,
          file_size_bytes: file.file_size_bytes,
          mime_type: file.mime_type,
          is_binary: file.is_binary,
          language_detected: file.language_detected,
          line_count: file.line_count,
          char_count: file.char_count
        },
        content: file.is_binary ? null : file.content_text,
        preview: file.content_preview
      }
    });
    
  } catch (error) {
    console.error('Error fetching file content:', error);
    res.status(500).json({
      success: false,
      message: error.message || 'Failed to fetch file content'
    });
  }
});

// Search repository files
router.get('/repository/:id/search', async (req, res) => {
  try {
    const { id } = req.params;
    const { q: query } = req.query;
    
    if (!query) {
      return res.status(400).json({
        success: false,
        message: 'Search query is required'
      });
    }

    const results = await fileStorageService.searchFileContent(id, query);
    
    res.json({
      success: true,
      data: {
        repository_id: id,
        search_query: query,
        results: results,
        total_results: results.length
      }
    });
    
  } catch (error) {
    console.error('Error searching repository:', error);
    res.status(500).json({
      success: false,
      message: error.message || 'Failed to search repository'
    });
  }
});

// List all repositories for a template
router.get('/template/:id/repositories', async (req, res) => {
  try {
    const { id } = req.params;
    
    const query = `
      SELECT gr.*, rs.local_path, rs.storage_status, rs.total_files_count, 
             rs.total_directories_count, rs.total_size_bytes, rs.download_completed_at
      FROM github_repositories gr
      LEFT JOIN repository_storage rs ON gr.id = rs.repository_id
      WHERE gr.template_id = $1 
      ORDER BY gr.created_at DESC
    `;
    
    const result = await database.query(query, [id]);
    
    const repositories = result.rows.map(repo => ({
      ...repo,
      metadata: JSON.parse(repo.metadata || '{}'),
      codebase_analysis: JSON.parse(repo.codebase_analysis || '{}')
    }));
    
    res.json({
      success: true,
      data: repositories
    });
    
  } catch (error) {
    console.error('Error fetching repositories:', error);
    res.status(500).json({
      success: false,
      message: error.message || 'Failed to fetch repositories'
    });
  }
});

// Download repository files (legacy endpoint for backward compatibility)
router.post('/download', async (req, res) => {
  try {
    const { repository_url, branch_name } = req.body;
    
    if (!repository_url) {
      return res.status(400).json({
        success: false,
        message: 'Repository URL is required'
      });
    }
    
    const { owner, repo, branch } = githubService.parseGitHubUrl(repository_url);
    const targetBranch = branch || branch_name || 'main';
    
    const result = await githubService.downloadRepository(owner, repo, targetBranch);
    
    if (result.success) {
      res.json({
        success: true,
        message: 'Repository downloaded successfully',
        data: result
      });
    } else {
      res.status(500).json({
        success: false,
        message: 'Failed to download repository',
        error: result.error
      });
    }
    
  } catch (error) {
    console.error('Error downloading repository:', error);
    res.status(500).json({
      success: false,
      message: error.message || 'Failed to download repository'
    });
  }
});

// Re-sync repository (re-download and update database)
router.post('/repository/:id/sync', async (req, res) => {
  try {
    const { id } = req.params;
    
    // Get repository info
    const repoQuery = 'SELECT * FROM github_repositories WHERE id = $1';
    const repoResult = await database.query(repoQuery, [id]);
    
    if (repoResult.rows.length === 0) {
      return res.status(404).json({
        success: false,
        message: 'Repository not found'
      });
    }
    
    const repository = repoResult.rows[0];
    const { owner, repo, branch } = githubService.parseGitHubUrl(repository.repository_url);
    
    // Clean up existing storage
    await githubService.cleanupRepositoryStorage(id);
    
    // Re-download with storage
    const downloadResult = await githubService.downloadRepositoryWithStorage(
      owner, repo, branch || repository.branch_name, id
    );
    
    // Update sync status
    await database.query(
      'UPDATE github_repositories SET sync_status = $1, updated_at = NOW() WHERE id = $2',
      [downloadResult.success ? 'synced' : 'error', id]
    );
    
    res.json({
      success: downloadResult.success,
      message: downloadResult.success ? 'Repository synced successfully' : 'Failed to sync repository',
      data: downloadResult
    });
    
  } catch (error) {
    console.error('Error syncing repository:', error);
    res.status(500).json({
      success: false,
      message: error.message || 'Failed to sync repository'
    });
  }
});

// Remove repository from template
router.delete('/repository/:id', async (req, res) => {
  try {
    const { id } = req.params;
    
    // Get repository info before deletion
    const getQuery = 'SELECT * FROM github_repositories WHERE id = $1';
    const getResult = await database.query(getQuery, [id]);
    
    if (getResult.rows.length === 0) {
      return res.status(404).json({
        success: false,
        message: 'Repository not found'
      });
    }
    
    const repository = getResult.rows[0];
    
    // Clean up file storage
    await githubService.cleanupRepositoryStorage(id);
    
    // Delete feature mappings first
    await database.query(
      'DELETE FROM feature_codebase_mappings WHERE repository_id = $1',
      [id]
    );
    
    // Delete repository record
    await database.query(
      'DELETE FROM github_repositories WHERE id = $1',
      [id]
    );
    
    res.json({
      success: true,
      message: 'Repository removed successfully',
      data: {
        removed_repository: repository.repository_name,
        template_id: repository.template_id
      }
    });
    
  } catch (error) {
    console.error('Error removing repository:', error);
    res.status(500).json({
      success: false,
      message: error.message || 'Failed to remove repository'
    });
  }
});

module.exports = router;
