const fs = require('fs');
const Stripe = require('stripe');

class StripeService {
  constructor(configPath = './config.json') {
    console.log('[STRIPE] ===== INITIALIZING STRIPE SERVICE =====');
    console.log('[STRIPE] Config path:', configPath);
    
    try {
      // Check if config file exists
      if (!fs.existsSync(configPath)) {
        const error = new Error(`Config file not found: ${configPath}`);
        console.error('[STRIPE] ERROR:', error.message);
        throw error;
      }
      
      console.log('[STRIPE] Config file exists, reading...');
      const configContent = fs.readFileSync(configPath, 'utf8');
      console.log('[STRIPE] Config file read successfully, length:', configContent.length);
      
      // Parse JSON
      try {
        this.config = JSON.parse(configContent);
        console.log('[STRIPE] Config JSON parsed successfully');
      } catch (parseError) {
        console.error('[STRIPE] ERROR: Failed to parse config JSON:', parseError.message);
        throw new Error(`Invalid JSON in config file: ${parseError.message}`);
      }
      
      // Check if stripe section exists
      if (!this.config.stripe) {
        console.error('[STRIPE] ERROR: stripe section missing in config');
        throw new Error('stripe section is missing in config.json');
      }
      
      console.log('[STRIPE] Stripe section found in config');
      
      // Check if secret_key exists
      if (!this.config.stripe.secret_key) {
        console.error('[STRIPE] ERROR: secret_key missing in stripe config');
        console.error('[STRIPE] Available stripe config keys:', Object.keys(this.config.stripe));
        throw new Error('secret_key is missing in stripe configuration');
      }
      
      console.log('[STRIPE] secret_key found in config');
      
      // Trim the secret key to remove any whitespace
      const secretKey = this.config.stripe.secret_key.trim();
      
      // Validate secret key format
      if (!secretKey.startsWith('sk_')) {
        console.error('[STRIPE] ERROR: Invalid secret key format (should start with sk_)');
        throw new Error('Invalid secret key format: must start with sk_');
      }
      
      console.log('[STRIPE] Secret key format validated');
      console.log('[STRIPE] Secret key length:', secretKey.length);
      console.log('[STRIPE] Secret key starts with:', secretKey.substring(0, 20) + '...');
      console.log('[STRIPE] Secret key ends with:', '...' + secretKey.substring(secretKey.length - 10));
      
      // Initialize Stripe SDK
      try {
        this.stripe = new Stripe(secretKey);
        console.log('[STRIPE] Stripe SDK initialized successfully');
      } catch (stripeInitError) {
        console.error('[STRIPE] ERROR: Failed to initialize Stripe SDK:', stripeInitError.message);
        throw new Error(`Failed to initialize Stripe SDK: ${stripeInitError.message}`);
      }
      
      // Set URLs
      this.successUrl = this.config.stripe.success_url || process.env.MY_DOMAIN + 'success';
      this.cancelUrl = this.config.stripe.cancel_url || process.env.MY_DOMAIN + 'cancel';
      console.log('[STRIPE] Success URL:', this.successUrl);
      console.log('[STRIPE] Cancel URL:', this.cancelUrl);
      
      console.log('[STRIPE] ===== STRIPE SERVICE INITIALIZED SUCCESSFULLY =====');
    } catch (error) {
      console.error('[STRIPE] ===== STRIPE SERVICE INITIALIZATION FAILED =====');
      console.error('[STRIPE] Error type:', error.constructor.name);
      console.error('[STRIPE] Error message:', error.message);
      if (error.stack) {
        console.error('[STRIPE] Error stack:', error.stack);
      }
      console.error('[STRIPE] =================================================');
      // Store initialization error for later access
      this.initializationError = {
        message: error.message,
        type: error.constructor.name,
        stack: error.stack
      };
      throw error;
    }
  }

  /**
   * Extract price from various formats
   * Examples: "$730.10 USD", "$730.10", "730.10", "730.10 USD"
   */
  extractPrice(priceString) {
    if (!priceString) return null;
    
    // Convert to string if not already
    const str = String(priceString);
    
    // Remove currency symbols and letters, keep only digits and decimal point
    const cleanPrice = str.replace(/[^0-9.]/g, '');
    
    // Parse to float
    const price = parseFloat(cleanPrice);
    
    if (isNaN(price) || price <= 0) {
      return null;
    }
    
    return price;
  }

  /**
   * Create Stripe Checkout Session
   * @param {Object} bookingData - Booking information
   * @param {string} bookingData.totalPrice - Total price (e.g., "$730.10 USD")
   * @param {string} bookingData.cruiseTitle - Cruise title
   * @param {string} bookingData.shipName - Ship name
   * @param {string} bookingData.sailDate - Sail date
   * @param {string} bookingData.guestName - Primary guest name
   * @param {string} bookingData.guestEmail - Primary guest email
   * @returns {Promise<string>} Checkout session URL
   */
  async createCheckoutSession(bookingData) {
    try {
      console.log('[STRIPE] Creating checkout session...');
      console.log('[STRIPE] Booking data:', JSON.stringify(bookingData, null, 2));
      
      // Extract price
      const priceInDollars = this.extractPrice(bookingData.totalPrice);
      
      if (!priceInDollars) {
        throw new Error(`Invalid price format: ${bookingData.totalPrice}`);
      }
      
      // Convert to cents (Stripe uses smallest currency unit)
      const priceInCents = Math.round(priceInDollars * 100);
      
      console.log('[STRIPE] Price extracted: $' + priceInDollars + ' (' + priceInCents + ' cents)');
      
      // Build product description
      const description = [
        bookingData.cruiseTitle,
        bookingData.shipName ? `Ship: ${bookingData.shipName}` : null,
        bookingData.sailDate ? `Sail Date: ${bookingData.sailDate}` : null,
        bookingData.guestName ? `Guest: ${bookingData.guestName}` : null
      ].filter(Boolean).join(' | ');
      
      // Prepare Stripe API request
      const stripeRequest = {
        payment_method_types: ['card'],
        line_items: [
          {
            price_data: {
              currency: 'usd',
              product_data: {
                name: bookingData.cruiseTitle || 'Cruise Booking',
                description: description,
              },
              unit_amount: priceInCents,
            },
            quantity: 1,
          },
        ],
        mode: 'payment',
        success_url: this.successUrl + '?session_id={CHECKOUT_SESSION_ID}',
        cancel_url: this.cancelUrl,
        customer_email: bookingData.guestEmail || undefined,
        metadata: {
          cruise_title: bookingData.cruiseTitle || '',
          ship_name: bookingData.shipName || '',
          sail_date: bookingData.sailDate || '',
          guest_name: bookingData.guestName || '',
          package_id: bookingData.packageId || '',
        },
      };
      
      // Log the request to Stripe API
      console.log('[STRIPE] ===== STRIPE API REQUEST =====');
      console.log('[STRIPE] Endpoint: POST /v1/checkout/sessions');
      console.log('[STRIPE] Request body:', JSON.stringify(stripeRequest, null, 2));
      console.log('[STRIPE] =============================');
      
      // Store request for error handling
      this.lastRequest = stripeRequest;
      
      // Create Stripe Checkout Session
      const session = await this.stripe.checkout.sessions.create(stripeRequest);
      
      // Log the response from Stripe API
      console.log('[STRIPE] ===== STRIPE API RESPONSE =====');
      console.log('[STRIPE] Status: Success');
      console.log('[STRIPE] Session ID:', session.id);
      console.log('[STRIPE] Checkout URL:', session.url);
      console.log('[STRIPE] Response data:', JSON.stringify({
        id: session.id,
        url: session.url,
        payment_status: session.payment_status,
        status: session.status,
        amount_total: session.amount_total,
        currency: session.currency
      }, null, 2));
      console.log('[STRIPE] ===============================');
      
      // Store response for error handling
      this.lastResponse = {
        id: session.id,
        url: session.url,
        payment_status: session.payment_status,
        status: session.status
      };
      
      return session.url;
    } catch (error) {
      // Log the error response from Stripe API
      console.error('[STRIPE] ===== STRIPE API ERROR RESPONSE =====');
      console.error('[STRIPE] Error message:', error.message);
      console.error('[STRIPE] Error type:', error.type || 'unknown');
      console.error('[STRIPE] Error code:', error.code || 'no code');
      console.error('[STRIPE] Error statusCode:', error.statusCode || 'no status');
      
      // Log request that caused the error
      if (this.lastRequest) {
        console.error('[STRIPE] Failed request body:', JSON.stringify(this.lastRequest, null, 2));
      }
      
      // Log full error details
      if (error.raw) {
        console.error('[STRIPE] Raw error response:', JSON.stringify(error.raw, null, 2));
      }
      if (error.requestId) {
        console.error('[STRIPE] Request ID:', error.requestId);
      }
      if (error.headers) {
        console.error('[STRIPE] Response headers:', JSON.stringify(error.headers, null, 2));
      }
      
      // Try to extract more error details
      try {
        const errorDetails = {
          message: error.message,
          type: error.type,
          code: error.code,
          statusCode: error.statusCode,
          requestId: error.requestId,
          raw: error.raw
        };
        console.error('[STRIPE] Full error details:', JSON.stringify(errorDetails, null, 2));
      } catch (e) {
        console.error('[STRIPE] Could not serialize error details');
      }
      
      console.error('[STRIPE] =====================================');
      
      // Store error for access in server.js
      this.lastError = {
        message: error.message,
        type: error.type,
        code: error.code,
        statusCode: error.statusCode,
        requestId: error.requestId,
        raw: error.raw,
        request: this.lastRequest
      };
      
      throw error;
    }
  }

  /**
   * Retrieve checkout session details
   * @param {string} sessionId - Stripe session ID
   * @returns {Promise<Object>} Session details
   */
  async getSession(sessionId) {
    try {
      const session = await this.stripe.checkout.sessions.retrieve(sessionId);
      return session;
    } catch (error) {
      console.error('[STRIPE] Error retrieving session:', error.message);
      throw error;
    }
  }
}

module.exports = StripeService;

