// routes/github-oauth.js
const express = require('express');
const router = express.Router();
const GitHubOAuthService = require('../services/github-oauth');

const oauthService = new GitHubOAuthService();

// Initiate GitHub OAuth flow (supports optional user_id). If redirect=1, do 302 to GitHub.
router.get('/auth/github', async (req, res) => {
  try {
    // If caller provided a state (e.g., containing repo context), use it; else generate one
    const state = (typeof req.query.state === 'string' && req.query.state.length > 0)
      ? req.query.state
      : Math.random().toString(36).substring(7);
    const userId =
      req.query.user_id ||
      (req.body && req.body.user_id) ||
      req.headers['x-user-id'] ||
      (req.cookies && (req.cookies.user_id || req.cookies.uid)) ||
      (req.session && req.session.user && (req.session.user.id || req.session.user.userId)) ||
      (req.user && (req.user.id || req.user.userId));

    if (!userId) {
      return res.status(400).json({
        success: false,
        message: 'user_id is required to initiate GitHub authentication'
      });
    }
    console.log('[GitHub OAuth] /auth/github resolved user_id =', userId || null);
    const authUrl = oauthService.getAuthUrl(state, userId || null);

    const shouldRedirect = ['1', 'true', 'yes'].includes(String(req.query.redirect || '').toLowerCase());
    if (shouldRedirect) {
      return res.redirect(302, authUrl);
    }

    res.json({
      success: true,
      data: {
        auth_url: authUrl,
        state: state
      }
    });

  } catch (error) {
    console.error('Error initiating GitHub OAuth:', error);
    res.status(500).json({
      success: false,
      message: error.message || 'Failed to initiate GitHub authentication'
    });
  }
});

// Handle GitHub OAuth callback
router.get('/auth/github/callback', async (req, res) => {
  try {
    const { code, state } = req.query;
    // user_id may arrive as query param or embedded in the state
    let user_id =
      req.query.user_id ||
      (req.body && req.body.user_id) ||
      req.headers['x-user-id'] ||
      (req.cookies && (req.cookies.user_id || req.cookies.uid)) ||
      (req.session && req.session.user && (req.session.user.id || req.session.user.userId)) ||
      (req.user && (req.user.id || req.user.userId));
    if (!user_id && typeof state === 'string' && state.includes('|uid=')) {
      try { user_id = state.split('|uid=')[1]; } catch {}
    }

    if (!user_id) {
      return res.status(400).json({
        success: false,
        message: 'user_id is required to complete GitHub authentication'
      });
    }

    if (!code) {
      return res.status(400).json({
        success: false,
        message: 'Authorization code missing'
      });
    }

    // Exchange code for token
    const accessToken = await oauthService.exchangeCodeForToken(code);
    
    // Get user info from GitHub
    const githubUser = await oauthService.getUserInfo(accessToken);
    
    // Store token with user context (if provided)
    console.log('[GitHub OAuth] callback about to store token for user_id =', user_id || null);
    const tokenRecord = await oauthService.storeToken(accessToken, githubUser, user_id || null);

    // Extract repo context from OAuth state for background processing
    let repoContext = null;
    try {
      if (typeof state === 'string' && state.includes('|repo=')) {
        const parts = Object.fromEntries(
          state.split('|').slice(1).map(kv => {
            const [k, ...rest] = kv.split('=');
            return [k, rest.join('=')];
          })
        );
        const repoUrl = parts.repo ? decodeURIComponent(parts.repo) : null;
        const branchName = parts.branch ? decodeURIComponent(parts.branch) : null;
        if (repoUrl) {
          repoContext = { repoUrl, branchName, userId: user_id };
          console.log('[GitHub OAuth] Repository context extracted for background processing:', repoUrl);
        }
      }
    } catch (err) {
      console.warn('[GitHub OAuth] Failed to extract repo context:', err.message);
    }

    // Redirect back to frontend IMMEDIATELY (before heavy cloning operation)
    const frontendUrl = process.env.FRONTEND_URL || 'https://dashboard.codenuk.com';
    try {
      const redirectUrl = `${frontendUrl}?github_connected=1&user=${encodeURIComponent(githubUser.login)}&processing=1`;
      console.log('[GitHub OAuth] Redirecting to:', redirectUrl);
      
      // Send redirect response immediately
      res.redirect(302, redirectUrl);
      
      // Now process repository attachment in background (after response is sent)
      if (repoContext) {
        setImmediate(async () => {
          try {
            console.log('[GitHub OAuth] Starting background repository attachment for:', repoContext.repoUrl);
            const GitHubIntegrationService = require('../services/github-integration.service');
            const database = require('../config/database');
            const githubService = new GitHubIntegrationService();
            const { owner, repo, branch } = githubService.parseGitHubUrl(repoContext.repoUrl);
            
            // Get metadata using authenticated Octokit
            const repositoryData = await githubService.fetchRepositoryMetadata(owner, repo);
            let actualBranch = repoContext.branchName || branch || repositoryData.default_branch || 'main';
            
            // Attempt analysis and sync with fallback
            const codebaseAnalysis = await githubService.analyzeCodebase(owner, repo, actualBranch, false);
            const insertQuery = `
              INSERT INTO all_repositories (
                repository_url, repository_name, owner_name, 
                branch_name, is_public, metadata, codebase_analysis, sync_status,
                requires_auth, user_id
              ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
              RETURNING *
            `;
            const insertValues = [
              repoContext.repoUrl,
              repo,
              owner,
              actualBranch,
              repositoryData.visibility !== 'private',
              JSON.stringify(repositoryData),
              JSON.stringify(codebaseAnalysis),
              'syncing',
              repositoryData.visibility === 'private',
              repoContext.userId || null,
            ];
            const insertResult = await database.query(insertQuery, insertValues);
            const repositoryRecord = insertResult.rows[0];
            
            // Clone repository
            const downloadResult = await githubService.syncRepositoryWithFallback(owner, repo, actualBranch, repositoryRecord.id, repositoryData.visibility !== 'private');
            const finalSyncStatus = downloadResult.success ? 'synced' : 'error';
            await database.query('UPDATE all_repositories SET sync_status = $1, updated_at = NOW() WHERE id = $2', [finalSyncStatus, repositoryRecord.id]);
            
            console.log(`✅ [GitHub OAuth] Background attachment completed: ${repo} - Status: ${finalSyncStatus}`);
          } catch (bgErr) {
            console.error('[GitHub OAuth] Background attachment failed:', bgErr.message);
          }
        });
      }
      
      return; // Response already sent
    } catch (e) {
      // Fallback to JSON if redirect fails
      return res.json({
        success: true,
        message: 'GitHub account connected successfully',
        data: {
          github_username: githubUser.login,
          github_user_id: githubUser.id,
          connected_at: tokenRecord.created_at
        }
      });
    }

  } catch (error) {
    console.error('Error handling GitHub callback:', error);
    res.status(500).json({
      success: false,
      message: error.message || 'Failed to connect GitHub account'
    });
  }
});

// Get GitHub connection status
router.get('/auth/github/status', async (req, res) => {
  try {
    const authStatus = await oauthService.getAuthStatus();

    res.json({
      success: true,
      data: authStatus
    });

  } catch (error) {
    console.error('Error checking GitHub status:', error);
    res.status(500).json({
      success: false,
      message: error.message || 'Failed to check GitHub connection status'
    });
  }
});

// Disconnect GitHub account
router.delete('/auth/github', async (req, res) => {
  try {
    await oauthService.revokeToken();

    res.json({
      success: true,
      message: 'GitHub account disconnected successfully'
    });

  } catch (error) {
    console.error('Error disconnecting GitHub:', error);
    res.status(500).json({
      success: false,
      message: error.message || 'Failed to disconnect GitHub account'
    });
  }
});

// Test repository access
router.post('/test-access', async (req, res) => {
  try {
    const { repository_url } = req.body;

    if (!repository_url) {
      return res.status(400).json({
        success: false,
        message: 'Repository URL is required'
      });
    }

    const GitHubIntegrationService = require('../services/github-integration.service');
    const githubService = new GitHubIntegrationService();
    
    const { owner, repo } = githubService.parseGitHubUrl(repository_url);
    const canAccess = await oauthService.canAccessRepository(owner, repo);

    res.json({
      success: true,
      data: {
        repository_url,
        owner,
        repo,
        can_access: canAccess
      }
    });

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

module.exports = router;
