const db = require('../database/db');
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

/**
 * Premium Service
 * Handles subscriptions, blockchain domains, and monetization features
 */
class PremiumService {

  /**
   * Check domain availability
   */
  async checkDomainAvailability(domain) {
    // Validate domain format
    if (!domain.endsWith('.aethex')) {
      throw new Error('Domain must end with .aethex');
    }

    const baseName = domain.replace('.aethex', '');

    // Check length (3-50 chars)
    if (baseName.length < 3 || baseName.length > 50) {
      throw new Error('Domain name must be 3-50 characters');
    }

    // Check valid characters (alphanumeric and hyphens)
    if (!/^[a-z0-9-]+$/.test(baseName)) {
      throw new Error('Domain can only contain lowercase letters, numbers, and hyphens');
    }

    // Check if already registered
    const existing = await db.query(
      `SELECT * FROM blockchain_domains WHERE domain = $1`,
      [domain]
    );

    if (existing.rows.length > 0) {
      // Generate alternatives
      const alternatives = this.generateAlternatives(baseName);

      return {
        available: false,
        domain: domain,
        suggestedAlternatives: alternatives
      };
    }

    return {
      available: true,
      domain: domain,
      price: 100.00 // Base price
    };
  }

  /**
   * Register premium .aethex domain
   */
  async registerDomain(userId, domain, walletAddress, paymentMethodId) {
    // Check availability
    const availability = await this.checkDomainAvailability(domain);

    if (!availability.available) {
      throw new Error('Domain not available');
    }

    // Create/get Stripe customer
    let customer = await this.getOrCreateStripeCustomer(userId);

    // Create subscription
    const subscription = await stripe.subscriptions.create({
      customer: customer.id,
      items: [
        {
          price: process.env.STRIPE_PREMIUM_YEARLY_PRICE_ID
        }
      ],
      default_payment_method: paymentMethodId,
      expand: ['latest_invoice.payment_intent']
    });

    if (subscription.status !== 'active' && subscription.status !== 'trialing') {
      throw new Error('Subscription creation failed');
    }

    // Store subscription
    const subResult = await db.query(
      `INSERT INTO premium_subscriptions 
       (user_id, tier, stripe_subscription_id, stripe_customer_id, current_period_end)
       VALUES ($1, 'premium', $2, $3, to_timestamp($4))
       RETURNING *`,
      [
        userId,
        subscription.id,
        customer.id,
        subscription.current_period_end
      ]
    );

    // Create domain record
    const expiresAt = new Date(subscription.current_period_end * 1000);
    const domainResult = await db.query(
      `INSERT INTO blockchain_domains 
       (domain, owner_user_id, wallet_address, expires_at, renewal_price_usd)
       VALUES ($1, $2, $3, $4, 100.00)
       RETURNING *`,
      [
        domain,
        userId,
        walletAddress,
        expiresAt
      ]
    );

    // Create premium identity
    await db.query(
      `INSERT INTO identities 
       (user_id, identifier, context, is_primary, display_name)
       VALUES ($1, $2, 'premium', true, $3)
       ON CONFLICT (user_id, identifier) DO NOTHING`,
      [
        userId,
        domain.replace('.aethex', '@aethex'),
        domain.split('.')[0]
      ]
    );

    // Update user tier
    await db.query(
      `UPDATE users SET premium_tier = 'premium' WHERE id = $1`,
      [userId]
    );

    // Log transaction
    await this.logPaymentTransaction(
      userId,
      'domain_purchase',
      100.00,
      subscription.latest_invoice?.payment_intent?.id,
      subscription.latest_invoice?.id,
      'succeeded'
    );

    // Note: NFT minting would happen via blockchain integration
    // For now, we'll log it for async processing
    console.log(`[Premium] Domain ${domain} registered, NFT minting queued for wallet ${walletAddress}`);

    return {
      domain: domainResult.rows[0],
      subscription: subResult.rows[0],
      nftMintTx: null // Would be populated by blockchain service
    };
  }

  /**
   * Subscribe to premium tier
   */
  async subscribe(userId, tier, paymentMethodId, billingPeriod = 'yearly') {
    // Get/create Stripe customer
    let customer = await this.getOrCreateStripeCustomer(userId);

    // Determine price ID
    const priceId = tier === 'premium'
      ? (billingPeriod === 'yearly' 
          ? process.env.STRIPE_PREMIUM_YEARLY_PRICE_ID
          : process.env.STRIPE_PREMIUM_MONTHLY_PRICE_ID)
      : process.env.STRIPE_ENTERPRISE_PRICE_ID;

    if (!priceId) {
      throw new Error('Invalid subscription tier or billing period');
    }

    // Create subscription
    const subscription = await stripe.subscriptions.create({
      customer: customer.id,
      items: [{ price: priceId }],
      default_payment_method: paymentMethodId,
      expand: ['latest_invoice.payment_intent']
    });

    // Determine amount
    const amount = tier === 'premium' 
      ? (billingPeriod === 'yearly' ? 100.00 : 10.00)
      : 500.00;

    // Store in database
    const result = await db.query(
      `INSERT INTO premium_subscriptions 
       (user_id, tier, stripe_subscription_id, stripe_customer_id, current_period_end)
       VALUES ($1, $2, $3, $4, to_timestamp($5))
       RETURNING *`,
      [
        userId,
        tier,
        subscription.id,
        customer.id,
        subscription.current_period_end
      ]
    );

    // Update user's tier
    await db.query(
      `UPDATE users SET premium_tier = $2 WHERE id = $1`,
      [userId, tier]
    );

    // Log transaction
    await this.logPaymentTransaction(
      userId,
      'subscription',
      amount,
      subscription.latest_invoice?.payment_intent?.id,
      subscription.latest_invoice?.id,
      'succeeded'
    );

    return result.rows[0];
  }

  /**
   * Get current subscription
   */
  async getSubscription(userId) {
    const result = await db.query(
      `SELECT * FROM premium_subscriptions 
       WHERE user_id = $1 AND status = 'active'
       ORDER BY created_at DESC
       LIMIT 1`,
      [userId]
    );

    if (result.rows.length === 0) {
      return null;
    }

    const sub = result.rows[0];

    // Get feature limits
    const limitsResult = await db.query(
      `SELECT * FROM feature_limits WHERE tier = $1`,
      [sub.tier]
    );

    const limits = limitsResult.rows[0];

    return {
      id: sub.id,
      tier: sub.tier,
      status: sub.status,
      currentPeriodStart: sub.current_period_start,
      currentPeriodEnd: sub.current_period_end,
      cancelAtPeriodEnd: sub.cancel_at_period_end,
      features: limits ? {
        maxFriends: limits.max_friends,
        storageGB: limits.max_storage_gb,
        voiceCalls: limits.voice_calls_enabled,
        videoCalls: limits.video_calls_enabled,
        customBranding: limits.custom_branding,
        analytics: limits.analytics_enabled,
        prioritySupport: limits.priority_support
      } : null
    };
  }

  /**
   * Cancel subscription
   */
  async cancelSubscription(userId, cancelAtPeriodEnd = true) {
    // Get subscription
    const result = await db.query(
      `SELECT * FROM premium_subscriptions 
       WHERE user_id = $1 AND status = 'active'
       ORDER BY created_at DESC
       LIMIT 1`,
      [userId]
    );

    if (result.rows.length === 0) {
      throw new Error('No active subscription found');
    }

    const sub = result.rows[0];

    if (cancelAtPeriodEnd) {
      // Cancel at period end
      await stripe.subscriptions.update(sub.stripe_subscription_id, {
        cancel_at_period_end: true
      });

      await db.query(
        `UPDATE premium_subscriptions 
         SET cancel_at_period_end = true 
         WHERE id = $1`,
        [sub.id]
      );
    } else {
      // Cancel immediately
      await stripe.subscriptions.cancel(sub.stripe_subscription_id);

      await db.query(
        `UPDATE premium_subscriptions 
         SET status = 'cancelled', cancelled_at = NOW() 
         WHERE id = $1`,
        [sub.id]
      );

      await db.query(
        `UPDATE users SET premium_tier = 'free' WHERE id = $1`,
        [userId]
      );
    }

    return {
      cancelAtPeriodEnd: cancelAtPeriodEnd,
      currentPeriodEnd: sub.current_period_end
    };
  }

  /**
   * Get user's domains
   */
  async getUserDomains(userId) {
    const result = await db.query(
      `SELECT * FROM blockchain_domains 
       WHERE owner_user_id = $1
       ORDER BY created_at DESC`,
      [userId]
    );

    return result.rows.map(row => ({
      id: row.id,
      domain: row.domain,
      verified: row.verified,
      nftTokenId: row.nft_token_id,
      expiresAt: row.expires_at,
      autoRenew: row.auto_renew,
      marketplaceListed: row.marketplace_listed,
      marketplacePrice: row.marketplace_price_usd ? parseFloat(row.marketplace_price_usd) : null
    }));
  }

  /**
   * List domain on marketplace
   */
  async listDomainOnMarketplace(domainId, userId, priceUSD) {
    // Verify ownership
    const domainResult = await db.query(
      `SELECT * FROM blockchain_domains WHERE id = $1 AND owner_user_id = $2`,
      [domainId, userId]
    );

    if (domainResult.rows.length === 0) {
      throw new Error('Domain not found or not owned by user');
    }

    // Update domain
    await db.query(
      `UPDATE blockchain_domains 
       SET marketplace_listed = true, marketplace_price_usd = $2, updated_at = NOW()
       WHERE id = $1`,
      [domainId, priceUSD]
    );

    return {
      domainId: domainId,
      listed: true,
      priceUSD: priceUSD
    };
  }

  /**
   * Remove domain from marketplace
   */
  async unlistDomainFromMarketplace(domainId, userId) {
    await db.query(
      `UPDATE blockchain_domains 
       SET marketplace_listed = false, marketplace_price_usd = NULL, updated_at = NOW()
       WHERE id = $1 AND owner_user_id = $2`,
      [domainId, userId]
    );

    return { success: true };
  }

  /**
   * Get marketplace listings
   */
  async getMarketplaceListings(limit = 20, offset = 0, sort = 'price_asc') {
    let orderBy = 'marketplace_price_usd ASC';

    if (sort === 'price_desc') {
      orderBy = 'marketplace_price_usd DESC';
    } else if (sort === 'recent') {
      orderBy = 'bd.updated_at DESC';
    }

    const result = await db.query(
      `SELECT 
         bd.*,
         u.username as owner_username
       FROM blockchain_domains bd
       JOIN users u ON bd.owner_user_id = u.id
       WHERE bd.marketplace_listed = true
       ORDER BY ${orderBy}
       LIMIT $1 OFFSET $2`,
      [limit, offset]
    );

    return result.rows.map(row => ({
      domainId: row.id,
      domain: row.domain,
      ownerUsername: row.owner_username,
      priceUSD: parseFloat(row.marketplace_price_usd),
      listedAt: row.updated_at,
      stats: {
        age: Math.floor((new Date() - new Date(row.created_at)) / (1000 * 60 * 60 * 24))
      }
    }));
  }

  /**
   * Track usage for analytics
   */
  async trackUsage(userId, type, value = 1) {
    const today = new Date().toISOString().split('T')[0];

    const field = type === 'message_sent' ? 'messages_sent' 
                : type === 'message_received' ? 'messages_received'
                : type === 'voice_minute' ? 'voice_minutes'
                : type === 'video_minute' ? 'video_minutes'
                : null;

    if (!field) return;

    await db.query(
      `INSERT INTO usage_analytics (user_id, date, ${field})
       VALUES ($1, $2, $3)
       ON CONFLICT (user_id, date)
       DO UPDATE SET ${field} = usage_analytics.${field} + $3`,
      [userId, today, value]
    );
  }

  /**
   * Get usage analytics
   */
  async getAnalytics(userId, period = '30d') {
    const days = parseInt(period.replace('d', ''));
    const startDate = new Date();
    startDate.setDate(startDate.getDate() - days);

    const result = await db.query(
      `SELECT 
         SUM(messages_sent) as messages_sent,
         SUM(messages_received) as messages_received,
         SUM(voice_minutes) as voice_minutes,
         SUM(video_minutes) as video_minutes,
         AVG(active_friends) as avg_active_friends
       FROM usage_analytics
       WHERE user_id = $1 AND date >= $2`,
      [userId, startDate.toISOString().split('T')[0]]
    );

    const stats = result.rows[0];

    return {
      period: period,
      messages: {
        sent: parseInt(stats.messages_sent) || 0,
        received: parseInt(stats.messages_received) || 0
      },
      calls: {
        voice: {
          totalMinutes: parseInt(stats.voice_minutes) || 0
        },
        video: {
          totalMinutes: parseInt(stats.video_minutes) || 0
        }
      },
      friends: {
        active: Math.round(parseFloat(stats.avg_active_friends)) || 0
      }
    };
  }

  /**
   * Get or create Stripe customer
   */
  async getOrCreateStripeCustomer(userId) {
    // Check if customer exists
    const subResult = await db.query(
      `SELECT stripe_customer_id FROM premium_subscriptions WHERE user_id = $1 LIMIT 1`,
      [userId]
    );

    if (subResult.rows.length > 0 && subResult.rows[0].stripe_customer_id) {
      return { id: subResult.rows[0].stripe_customer_id };
    }

    // Get user email
    const userResult = await db.query(
      `SELECT email, username FROM users WHERE id = $1`,
      [userId]
    );

    if (userResult.rows.length === 0) {
      throw new Error('User not found');
    }

    const user = userResult.rows[0];

    // Create Stripe customer
    const customer = await stripe.customers.create({
      email: user.email,
      name: user.username,
      metadata: {
        userId: userId
      }
    });

    return customer;
  }

  /**
   * Generate alternative domain suggestions
   */
  generateAlternatives(baseName) {
    return [
      `${baseName}-dev.aethex`,
      `${baseName}-games.aethex`,
      `${baseName}-official.aethex`,
      `${baseName}pro.aethex`,
      `${baseName}hq.aethex`
    ];
  }

  /**
   * Log payment transaction
   */
  async logPaymentTransaction(userId, type, amount, paymentIntentId, invoiceId, status) {
    await db.query(
      `INSERT INTO payment_transactions 
       (user_id, transaction_type, amount_usd, stripe_payment_intent_id, stripe_invoice_id, status)
       VALUES ($1, $2, $3, $4, $5, $6)`,
      [userId, type, amount, paymentIntentId, invoiceId, status]
    );
  }

  /**
   * Check if user can access premium feature
   */
  async checkFeatureAccess(userId, feature) {
    const user = await db.query(
      `SELECT premium_tier FROM users WHERE id = $1`,
      [userId]
    );

    if (user.rows.length === 0) {
      return false;
    }

    const tier = user.rows[0].premium_tier || 'free';

    const limits = await db.query(
      `SELECT * FROM feature_limits WHERE tier = $1`,
      [tier]
    );

    if (limits.rows.length === 0) {
      return false;
    }

    const featureLimits = limits.rows[0];

    switch (feature) {
      case 'voice_calls':
        return featureLimits.voice_calls_enabled;
      case 'video_calls':
        return featureLimits.video_calls_enabled;
      case 'analytics':
        return featureLimits.analytics_enabled;
      case 'custom_branding':
        return featureLimits.custom_branding;
      default:
        return false;
    }
  }
}

module.exports = new PremiumService();
