import { db } from '../config/database.js';
import { randomUUID } from 'crypto';

export class Order {
  /**
   * Create a new order in the database
   * @param {Object} orderData - Order data
   * @param {string} orderData.stripeSessionId - Stripe checkout session ID
   * @param {string} orderData.customerEmail - Customer email
   * @param {number} orderData.tons - Carbon offset tons
   * @param {number} orderData.portfolioId - Portfolio ID
   * @param {number} orderData.baseAmount - Base amount in cents
   * @param {number} orderData.processingFee - Processing fee in cents
   * @param {number} orderData.totalAmount - Total amount in cents
   * @param {string} orderData.currency - Currency code (default: USD)
   * @returns {Object} Created order
   */
  static create({
    stripeSessionId,
    customerEmail,
    tons,
    portfolioId,
    baseAmount,
    processingFee,
    totalAmount,
    currency = 'USD'
  }) {
    const id = randomUUID();
    const now = new Date().toISOString();

    const stmt = db.prepare(`
      INSERT INTO orders (
        id, stripe_session_id, customer_email, tons, portfolio_id,
        base_amount, processing_fee, total_amount, currency,
        status, created_at, updated_at
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending', ?, ?)
    `);

    stmt.run(
      id,
      stripeSessionId,
      customerEmail,
      tons,
      portfolioId,
      baseAmount,
      processingFee,
      totalAmount,
      currency,
      now,
      now
    );

    return this.findById(id);
  }

  /**
   * Find order by ID
   * @param {string} id - Order ID
   * @returns {Object|null} Order or null
   */
  static findById(id) {
    const stmt = db.prepare('SELECT * FROM orders WHERE id = ?');
    return stmt.get(id);
  }

  /**
   * Find order by Stripe session ID
   * @param {string} sessionId - Stripe session ID
   * @returns {Object|null} Order or null
   */
  static findBySessionId(sessionId) {
    const stmt = db.prepare('SELECT * FROM orders WHERE stripe_session_id = ?');
    return stmt.get(sessionId);
  }

  /**
   * Update order status
   * @param {string} id - Order ID
   * @param {string} status - New status (pending, paid, fulfilled, failed)
   * @returns {Object} Updated order
   */
  static updateStatus(id, status) {
    const now = new Date().toISOString();
    const stmt = db.prepare('UPDATE orders SET status = ?, updated_at = ? WHERE id = ?');
    stmt.run(status, now, id);
    return this.findById(id);
  }

  /**
   * Update order with payment intent ID
   * @param {string} id - Order ID
   * @param {string} paymentIntentId - Stripe payment intent ID
   * @returns {Object} Updated order
   */
  static updatePaymentIntent(id, paymentIntentId) {
    const now = new Date().toISOString();
    const stmt = db.prepare('UPDATE orders SET stripe_payment_intent = ?, updated_at = ? WHERE id = ?');
    stmt.run(paymentIntentId, now, id);
    return this.findById(id);
  }

  /**
   * Update order with Wren order ID after fulfillment
   * @param {string} id - Order ID
   * @param {string} wrenOrderId - Wren API order ID
   * @param {string} status - Order status (fulfilled or failed)
   * @returns {Object} Updated order
   */
  static updateWrenOrder(id, wrenOrderId, status = 'fulfilled') {
    const now = new Date().toISOString();
    const stmt = db.prepare('UPDATE orders SET wren_order_id = ?, status = ?, updated_at = ? WHERE id = ?');
    stmt.run(wrenOrderId, status, now, id);
    return this.findById(id);
  }

  /**
   * Atomically update payment intent and status
   * This prevents race conditions by updating both fields in a single transaction
   * @param {string} id - Order ID
   * @param {string} paymentIntentId - Stripe payment intent ID
   * @param {string} status - New status
   * @returns {Object} Updated order
   */
  static updatePaymentAndStatus(id, paymentIntentId, status) {
    const now = new Date().toISOString();
    const stmt = db.prepare(`
      UPDATE orders
      SET stripe_payment_intent = ?, status = ?, updated_at = ?
      WHERE id = ?
    `);
    stmt.run(paymentIntentId, status, now, id);
    return this.findById(id);
  }

  /**
   * Get all orders (with optional filters)
   * @param {Object} filters - Filter options
   * @param {string} filters.status - Filter by status
   * @param {number} filters.limit - Limit results
   * @param {number} filters.offset - Offset for pagination
   * @returns {Array} Array of orders
   */
  static findAll({ status, limit = 100, offset = 0 } = {}) {
    let query = 'SELECT * FROM orders';
    const params = [];

    if (status) {
      query += ' WHERE status = ?';
      params.push(status);
    }

    query += ' ORDER BY created_at DESC LIMIT ? OFFSET ?';
    params.push(limit, offset);

    const stmt = db.prepare(query);
    return stmt.all(...params);
  }

  /**
   * Get order count by status
   * @returns {Object} Count by status
   */
  static getStatusCounts() {
    const stmt = db.prepare('SELECT status, COUNT(*) as count FROM orders GROUP BY status');
    const rows = stmt.all();

    return rows.reduce((acc, row) => {
      acc[row.status] = row.count;
      return acc;
    }, {});
  }

  /**
   * Delete order (for testing purposes only)
   * @param {string} id - Order ID
   * @returns {boolean} Success
   */
  static delete(id) {
    const stmt = db.prepare('DELETE FROM orders WHERE id = ?');
    const result = stmt.run(id);
    return result.changes > 0;
  }
}

export default Order;
