// packages/functions/src/firebase/billing/createCheckoutSession.ts

/**
 * @fileoverview Create checkout session Firebase function
 * @description Firebase callable function for creating Stripe checkout sessions
 *
 * @version 0.0.1
 * @since 0.0.1
 * @author AMBROISE PARK Consulting
 */

import { getFirebaseAdminAuth } from '@donotdev/firebase/server';
import { logger } from 'firebase-functions/v2';

import type {
  CreateCheckoutSessionRequest,
  StripeBackConfig,
} from '@donotdev/core/server';
import { STRIPE_MODES } from '@donotdev/core/server';
import { CreateCheckoutSessionRequestSchema } from '@donotdev/core/server';

import { handleError } from '../../shared/errorHandling.js';
import {
  validateUrl,
  validateMetadata,
} from '../../shared/utils/validation.js';
import { stripe, validateStripeEnvironment } from '../../shared/utils.js';
import { createBaseFunction } from '../baseFunction.js';
import { STRIPE_CONFIG } from '../config/constants.js';

import type { CallableRequest } from 'firebase-functions/v2/https';

/**
 * Business logic for creating Stripe checkout session
 */
async function createCheckoutSessionLogic(
  data: CreateCheckoutSessionRequest,
  context: {
    uid: string;
    request: CallableRequest<CreateCheckoutSessionRequest>;
  },
  billingConfig: StripeBackConfig
) {
  try {
    validateStripeEnvironment();
  } catch (error) {
    logger.error(
      '[createCheckoutSession] Stripe environment validation failed',
      {
        error: error instanceof Error ? error.message : String(error),
      }
    );
    throw error;
  }

  const {
    priceId,
    userId,
    customerEmail,
    metadata = {},
    successUrl,
    cancelUrl,
    allowPromotionCodes = true,
    mode = 'payment',
  } = data;

  logger.debug('[createCheckoutSession] Processing request', {
    priceId,
    userId,
    hasMetadata: !!metadata,
    metadataKeys: Object.keys(metadata),
  });

  // ✅ VALIDATE: priceId exists in billing config
  const configKey = metadata.billingConfigKey;
  if (!configKey) {
    logger.error('[createCheckoutSession] Missing billingConfigKey', {
      metadata,
    });
    throw handleError(new Error('Missing billingConfigKey in metadata'));
  }

  const billingItem = billingConfig[configKey];
  if (!billingItem) {
    logger.error('[createCheckoutSession] Invalid billing config key', {
      configKey,
      availableKeys: Object.keys(billingConfig),
    });
    throw handleError(new Error(`Invalid billing config key: ${configKey}`));
  }

  // ✅ VALIDATE: priceId matches config
  if (billingItem.priceId !== priceId) {
    logger.error('[createCheckoutSession] Price ID mismatch', {
      requested: priceId,
      expected: billingItem.priceId,
      configKey,
    });
    throw handleError(new Error('Price ID mismatch with configuration'));
  }

  // Verify user exists
  let user;
  try {
    user = await getFirebaseAdminAuth().getUser(userId);
  } catch (error) {
    logger.error('[createCheckoutSession] Failed to get user', {
      userId,
      error: error instanceof Error ? error.message : String(error),
    });
    throw handleError(new Error(`User not found: ${userId}`));
  }

  // Validate URLs from request parameters (frontend responsibility)
  try {
    validateUrl(successUrl, 'success');
    validateUrl(cancelUrl, 'cancel');
  } catch (error) {
    logger.error('[createCheckoutSession] URL validation failed', {
      successUrl,
      cancelUrl,
      error: error instanceof Error ? error.message : String(error),
    });
    throw error;
  }

  // Validate and sanitize metadata
  let sanitizedMetadata: Record<string, string>;
  try {
    sanitizedMetadata = validateMetadata(metadata);
  } catch (error) {
    logger.error('[createCheckoutSession] Metadata validation failed', {
      metadata,
      error: error instanceof Error ? error.message : String(error),
    });
    throw error;
  }

  // Create checkout session with Stripe
  let session;
  try {
    session = await stripe.checkout.sessions.create({
      mode,
      line_items: [
        {
          price: priceId,
          quantity: 1,
        },
      ],
      customer_email: customerEmail || user.email || undefined,
      success_url: successUrl,
      cancel_url: cancelUrl,
      allow_promotion_codes: allowPromotionCodes,
      metadata: {
        userId,
        firebaseUid: userId,
        billingConfigKey: configKey, // ✅ ENSURE THIS IS SET
        ...sanitizedMetadata,
      },
      // For subscriptions, automatically create customer in Stripe
      ...(mode === 'subscription' && {
        subscription_data: {
          metadata: {
            userId,
            firebaseUid: userId,
            billingConfigKey: configKey, // ✅ ENSURE THIS IS SET
            ...metadata,
          },
        },
      }),
    });
  } catch (error) {
    logger.error('[createCheckoutSession] Stripe API call failed', {
      priceId,
      userId,
      error: error instanceof Error ? error.message : String(error),
      stripeError: (error as any).type || (error as any).code,
    });
    throw handleError(
      new Error(
        `Stripe checkout session creation failed: ${error instanceof Error ? error.message : String(error)}`
      )
    );
  }

  if (!session.url) {
    logger.error('[createCheckoutSession] Session created but no URL', {
      sessionId: session.id,
    });
    throw handleError(new Error('Failed to create checkout session URL'));
  }

  logger.info('[createCheckoutSession] Checkout session created successfully', {
    sessionId: session.id,
    userId,
    priceId,
  });

  return {
    sessionId: session.id,
    sessionUrl: session.url,
  };
}

/**
 * Create Firebase function for checkout session creation
 *
 * @param billingConfig - Billing configuration with product definitions
 * @returns Firebase function for checkout session creation
 *
 * @example
 * const createCheckout = createCheckoutSession(billingConfig);
 * const result = await createCheckout({
 *   priceId: 'price_xxx',
 *   userId: 'user123',
 *   metadata: { billingConfigKey: 'early_bird' }
 * });
 * window.location.href = result.data.sessionUrl;
 */
export function createCheckoutSession(billingConfig: StripeBackConfig) {
  return createBaseFunction<
    CreateCheckoutSessionRequest,
    { sessionId: string; sessionUrl: string }
  >(
    STRIPE_CONFIG,
    CreateCheckoutSessionRequestSchema,
    'create_checkout_session',
    (data, context) => createCheckoutSessionLogic(data, context, billingConfig) // ✅ PASS CONFIG
  );
}
