import Stripe from 'stripe';
import { Settings } from '@/models/Settings';
import { decryptSecret } from './security';
import { Order } from '@/models/Order';
import { Course } from '@/models/Course';
import { Subscription } from '@/models/Subscription';
import { CoursePurchaseHistory } from '@/models/CoursePurchaseHistory';
import { Student } from '@/models/Student';

export interface StripeConfig {
  mode: 'test' | 'live';
  isEnabled: boolean;
  publishableKey: string;
  secretKey: string;
}

/**
 * Dynamically resolves the active Stripe configuration from MongoDB Settings table.
 * Strictly keeps secret keys on the server.
 */
export async function getStripeConfig(): Promise<StripeConfig> {
  const settings = await Settings.getSettings();
  const mode = (settings.stripe?.mode as 'test' | 'live') || 'test';
  const isEnabled = settings.stripe?.isEnabled ?? true;

  let publishableKey = '';
  let secretKey = '';

  if (mode === 'live') {
    publishableKey = settings.stripe?.livePublishableKey || settings.stripe?.publishableKey || process.env.STRIPE_LIVE_PUBLISHABLE_KEY || '';
    const rawSecret = settings.stripe?.liveSecretKeyEncrypted || settings.stripe?.secretKeyEncrypted || process.env.STRIPE_LIVE_SECRET_KEY || '';
    secretKey = rawSecret ? decryptSecret(rawSecret) : '';
  } else {
    publishableKey = settings.stripe?.testPublishableKey || settings.stripe?.publishableKey || process.env.STRIPE_TEST_PUBLISHABLE_KEY || process.env.STRIPE_PUBLISHABLE_KEY || '';
    const rawSecret = settings.stripe?.testSecretKeyEncrypted || settings.stripe?.secretKeyEncrypted || process.env.STRIPE_TEST_SECRET_KEY || process.env.STRIPE_SECRET_KEY || '';
    secretKey = rawSecret ? decryptSecret(rawSecret) : '';
  }

  return {
    mode,
    isEnabled,
    publishableKey,
    secretKey,
  };
}

/**
 * Initializes and returns an authenticated Stripe SDK instance using resolved active secret key.
 */
export async function getStripeInstance(): Promise<{ stripe: Stripe; config: StripeConfig }> {
  const config = await getStripeConfig();

  if (!config.secretKey) {
    throw new Error(`Stripe secret key is not configured for ${config.mode.toUpperCase()} mode in database settings.`);
  }

  const stripe = new Stripe(config.secretKey, {
    apiVersion: '2023-10-16' as any,
  });

  return { stripe, config };
}

/**
 * Creates an Order in database ONLY when payment is successfully confirmed,
 * then grants Course Subscriptions and records CoursePurchaseHistory.
 * Prevents creation of unfulfilled/abandoned pending orders in MongoDB.
 */
export async function createAndFulfillStripeOrderFromSession(sessionData: any) {
  const gatewayTransactionId = (sessionData.payment_intent as string) || sessionData.id;

  // Check if Order already exists by transaction ID (Idempotency check)
  let order = await Order.findOne({ gatewayTransactionId });

  if (!order && sessionData.metadata?.orderId) {
    order = await Order.findById(sessionData.metadata.orderId);
  }

  if (order && order.status === 'succeeded') {
    return order; // Already processed & fulfilled
  }

  if (!order) {
    const studentId = sessionData.metadata?.studentId;
    const courseId = sessionData.metadata?.courseId;
    let lessons: string[] = [];

    try {
      if (sessionData.metadata?.lessons) {
        lessons = JSON.parse(sessionData.metadata.lessons);
      }
    } catch {
      lessons = [];
    }

    const amount = sessionData.amount_total
      ? sessionData.amount_total / 100
      : Number(sessionData.metadata?.amount || 0);

    if (!studentId || !courseId) {
      throw new Error('Missing studentId or courseId in Stripe session metadata');
    }

    // Create Order in MongoDB ONLY after payment is verified successful
    order = await Order.create({
      student: studentId,
      courseId: courseId,
      lessons: lessons,
      gateway: 'stripe',
      gatewayTransactionId: gatewayTransactionId,
      gatewayResponse: sessionData,
      amount: amount,
      currency: (sessionData.currency || 'EUR').toUpperCase(),
      paymentRequired: true,
      status: 'succeeded',
      initiatedAt: new Date(),
      confirmedAt: new Date(),
    });
  } else {
    // If pending order existed, update status to succeeded
    order.status = 'succeeded';
    order.gateway = 'stripe';
    order.gatewayTransactionId = gatewayTransactionId;
    order.gatewayResponse = sessionData;
    order.confirmedAt = new Date();
    await order.save();
  }

  // Get active settings for default validity
  const settings = await Settings.getSettings();

  // Create CoursePurchaseHistory record if not exists
  const existingHistory = await CoursePurchaseHistory.findOne({ order: order._id });
  if (!existingHistory) {
    await CoursePurchaseHistory.create({
      student: order.student,
      order: order._id,
      courseId: order.courseId,
      lessons: order.lessons || [],
      amountPaid: order.amount,
      currency: order.currency || 'EUR',
      discountApplied: 0,
      paymentMethod: 'stripe',
      transactionId: gatewayTransactionId,
      paymentStatus: 'completed',
      purchasedAt: new Date(),
    });
  }

  // Grant active subscriptions to student
  const courses = await Course.find({ _id: order.courseId });
  for (const course of courses) {
    const validityMonths = course.validityMonths || settings.defaultCourseExpiryMonths || 4;
    const startDate = new Date();
    const expiryDate = new Date();
    expiryDate.setMonth(expiryDate.getMonth() + validityMonths);

    const existingSub = await Subscription.findOne({
      student: order.student,
      course: course._id,
    });

    if (existingSub) {
      existingSub.expiryDate = expiryDate;
      existingSub.status = 'active';

      // Merge new lesson IDs with existing unlocked lessons without duplicates
      if (Array.isArray(order.lessons) && order.lessons.length > 0) {
        const mergedLessons = Array.from(
          new Set([
            ...(existingSub.lessons || []).map((id) => id.toString()),
            ...order.lessons.map((id) => id.toString()),
          ])
        );
        existingSub.lessons = mergedLessons as any;
      }

      await existingSub.save();
    } else {
      await Subscription.create({
        student: order.student,
        course: course._id,
        lessons: order.lessons || [],
        order: order._id,
        startDate,
        expiryDate,
        status: 'active',
        completedChapters: [],
        completedPercent: 0,
        lastWatchedPositionSeconds: 0,
      });
    }
  }

  return order;
}

export async function fulfillStripeOrder(orderId: string, gatewayTransactionId: string, gatewayResponse?: Record<string, any>) {
  const order = await Order.findById(orderId);
  if (!order) {
    return createAndFulfillStripeOrderFromSession({
      id: gatewayTransactionId,
      payment_intent: gatewayTransactionId,
      metadata: { orderId },
      ...gatewayResponse,
    });
  }

  return createAndFulfillStripeOrderFromSession({
    ...gatewayResponse,
    id: gatewayTransactionId,
    payment_intent: gatewayTransactionId,
    metadata: { ...gatewayResponse?.metadata, orderId: order._id.toString() },
  });
}
