// services/gitea-oauth.js
const database = require('../config/database');

const axios = require('axios');

class GiteaOAuthService {
  constructor() {
    this.clientId = process.env.GITEA_CLIENT_ID;
    this.clientSecret = process.env.GITEA_CLIENT_SECRET;
    this.baseUrl = (process.env.GITEA_BASE_URL || 'https://gitea.com').replace(/\/$/, '');
    this.redirectUri = process.env.GITEA_REDIRECT_URI || 'http://localhost:8000/api/vcs/gitea/auth/callback';
  }

  getAuthUrl(state) {
    if (!this.clientId) throw new Error('Gitea OAuth not configured');
    const authUrl = `${this.baseUrl}/login/oauth/authorize`;
    const params = new URLSearchParams({
      client_id: this.clientId,
      redirect_uri: this.redirectUri,
      response_type: 'code',
      // Request both user and repository read scopes
      scope: 'read:user read:repository write:repository',
      state
    });
    const fullUrl = `${authUrl}?${params.toString()}`;
    console.log(`🔗 [GITEA OAUTH] Generated auth URL: ${fullUrl}`);
    return fullUrl;
  }

  async exchangeCodeForToken(code) {
    const tokenUrl = `${this.baseUrl}/login/oauth/access_token`;
    console.log(`🔄 [GITEA OAUTH] Exchanging code for token at: ${tokenUrl}`);
    console.log(`🔧 [GITEA OAUTH] Config - Base URL: ${this.baseUrl}, Client ID: ${this.clientId?.substring(0, 8)}...`);
    // Validate required configuration
    if (!this.clientId) {
      throw new Error('GITEA_CLIENT_ID is not configured');
    }
    if (!this.clientSecret) {
      throw new Error('GITEA_CLIENT_SECRET is not configured');
    }
    try {
      const response = await axios.post(tokenUrl, new URLSearchParams({
        client_id: this.clientId,
        client_secret: this.clientSecret,
        code,
        grant_type: 'authorization_code',
        redirect_uri: this.redirectUri,
        scope: 'read:user read:repository write:repository'
      }), {
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'Accept': 'application/json',
          'User-Agent': 'CodeNuk-GitIntegration/1.0'
        },
        timeout: 30000,
        maxRedirects: 0,
        // Add network configuration to handle connectivity issues
        httpsAgent: new (require('https').Agent)({
          keepAlive: true,
          timeout: 30000,
          // Force IPv4 to avoid IPv6 connectivity issues
          family: 4
        }),
        // Add retry configuration
        validateStatus: function (status) {
          return status >= 200 && status < 300;
        }
      });
      console.log(`📥 [GITEA OAUTH] Response status: ${response.status} ${response.statusText}`);
      console.log(`📥 [GITEA OAUTH] Response data:`, response.data);
      if (response.data.error) {
        console.error(`❌ [GITEA OAUTH] Token exchange failed:`, response.data);
        throw new Error(response.data.error_description || response.data.error || 'Gitea token exchange failed');
      }
      if (!response.data.access_token) {
        console.error(`❌ [GITEA OAUTH] No access token in response:`, response.data);
        throw new Error('No access token received from Gitea OAuth');
      }
      console.log(`✅ [GITEA OAUTH] Token exchange successful`);
      return response.data.access_token;
    } catch (e) {
      console.error(`❌ [GITEA OAUTH] Token exchange error:`, e);
      // Handle AggregateError (multiple network errors)
      if (e.name === 'AggregateError' && e.errors && e.errors.length > 0) {
        const firstError = e.errors[0];
        if (firstError.code === 'ETIMEDOUT') {
          throw new Error(`Gitea OAuth timeout: Request to ${tokenUrl} timed out after 30 seconds`);
        } else if (firstError.code === 'ENOTFOUND' || firstError.code === 'ECONNREFUSED') {
          throw new Error(`Gitea OAuth network error: Cannot connect to ${this.baseUrl}. Please check your network connection and GITEA_BASE_URL configuration`);
        } else {
          throw new Error(`Gitea OAuth network error: ${firstError.message || 'Connection failed'}`);
        }
      }
      if (e.code === 'ECONNABORTED' || e.message.includes('timeout')) {
        throw new Error(`Gitea OAuth timeout: Request to ${tokenUrl} timed out after 30 seconds`);
      } else if (e.code === 'ENOTFOUND' || e.code === 'ECONNREFUSED' || e.message.includes('Network Error')) {
        throw new Error(`Gitea OAuth network error: Cannot connect to ${this.baseUrl}. Please check your network connection and GITEA_BASE_URL configuration`);
      } else if (e.response) {
        // Handle HTTP error responses
        const status = e.response.status;
        const data = e.response.data;
        throw new Error(`Gitea OAuth HTTP error ${status}: ${JSON.stringify(data)}`);
      } else {
        throw new Error(`Gitea OAuth error: ${e.message || 'Unknown error occurred'}`);
      }
    }
  
  }

  async getUserInfo(accessToken) {

    const userUrl = `${this.baseUrl}/api/v1/user`;
    console.log(`🔄 [GITEA OAUTH] Fetching user info from: ${userUrl}`);
    try {
      const response = await axios.get(userUrl, {
        headers: {
          'Authorization': `token ${accessToken}`,
          'Accept': 'application/json',
          'User-Agent': 'CodeNuk-GitIntegration/1.0'
        },
        timeout: 15000,
        // Add network configuration to handle connectivity issues
        httpsAgent: new (require('https').Agent)({
          keepAlive: true,
          timeout: 15000,
          // Force IPv4 to avoid IPv6 connectivity issues
          family: 4
        }),
        // Add retry configuration
        validateStatus: function (status) {
          return status >= 200 && status < 300;
        }
      });
      console.log(`📥 [GITEA OAUTH] User info response status: ${response.status} ${response.statusText}`);
      console.log(`✅ [GITEA OAUTH] User info retrieved successfully for: ${response.data.login || response.data.username}`);
      return response.data;
    } catch (e) {
      console.error(`❌ [GITEA OAUTH] User info error:`, e);      
      if (e.response) {
        console.error(`❌ [GITEA OAUTH] User info failed:`, e.response.data);
        throw new Error(`Failed to fetch Gitea user (${e.response.status}): ${JSON.stringify(e.response.data)}`);
      } else if (e.code === 'ECONNABORTED' || e.message.includes('timeout')) {
        throw new Error('Gitea user info timeout: Request timed out after 15 seconds');
      } else if (e.code === 'ENOTFOUND' || e.code === 'ECONNREFUSED' || e.message.includes('Network Error')) {
        throw new Error(`Gitea user info network error: Cannot connect to ${this.baseUrl}`);
      } else {
        throw e;
      }
    }
   
  }

  async storeToken(accessToken, user) {
    const result = await database.query(
      `INSERT INTO gitea_user_tokens (access_token, gitea_username, gitea_user_id, scopes, expires_at)
       VALUES ($1, $2, $3, $4, $5)
       ON CONFLICT (id) DO UPDATE SET access_token = EXCLUDED.access_token, gitea_username = EXCLUDED.gitea_username, gitea_user_id = EXCLUDED.gitea_user_id, scopes = EXCLUDED.scopes, expires_at = EXCLUDED.expires_at, updated_at = NOW()
       RETURNING *`,
      [accessToken, user.login, user.id, JSON.stringify(['read:user','read:repository']), null]
    );
    return result.rows[0];
  }

  async getToken() {
    const r = await database.query('SELECT * FROM gitea_user_tokens ORDER BY created_at DESC LIMIT 1');
    return r.rows[0];
  }
}

module.exports = GiteaOAuthService;


