/**
 * @ai-summary Grace period expiration job
 * @ai-context Processes expired grace periods and downgrades subscriptions to free tier
 */

import { Pool } from 'pg';
import { logger } from '../../../core/logging/logger';
import { NotificationsService } from '../../notifications/domain/notifications.service';

let jobPool: Pool | null = null;
let notificationsService: NotificationsService | null = null;

export function setGracePeriodJobPool(pool: Pool): void {
  jobPool = pool;
  notificationsService = new NotificationsService();
}

interface GracePeriodResult {
  processed: number;
  downgraded: number;
  errors: string[];
}

/**
 * Process grace period expirations
 * Finds subscriptions with expired grace periods and downgrades them to free tier
 */
export async function processGracePeriodExpirations(): Promise<GracePeriodResult> {
  if (!jobPool) {
    throw new Error('Grace period job pool not initialized');
  }

  const result: GracePeriodResult = {
    processed: 0,
    downgraded: 0,
    errors: [],
  };

  const client = await jobPool.connect();

  try {
    // Find subscriptions with expired grace periods (join with user_profiles for notification)
    const query = `
      SELECT
        s.id,
        s.user_id,
        s.tier,
        s.stripe_subscription_id,
        up.email as user_email,
        up.notification_email,
        up.display_name
      FROM subscriptions s
      LEFT JOIN user_profiles up ON s.user_id = up.auth0_sub
      WHERE s.status = 'past_due'
        AND s.grace_period_end < NOW()
      ORDER BY s.grace_period_end ASC
    `;

    const queryResult = await client.query(query);
    const expiredSubscriptions = queryResult.rows;

    result.processed = expiredSubscriptions.length;

    logger.info('Processing expired grace periods', {
      count: expiredSubscriptions.length,
    });

    // Process each expired subscription
    for (const subscription of expiredSubscriptions) {
      try {
        // Start transaction for this subscription
        await client.query('BEGIN');

        // Update subscription to free tier and unpaid status
        const updateQuery = `
          UPDATE subscriptions
          SET
            tier = 'free',
            status = 'unpaid',
            stripe_subscription_id = NULL,
            billing_cycle = NULL,
            current_period_start = NULL,
            current_period_end = NULL,
            grace_period_end = NULL,
            cancel_at_period_end = false,
            updated_at = NOW()
          WHERE id = $1
        `;

        await client.query(updateQuery, [subscription.id]);

        // Sync tier to user_profiles table (user_id is auth0_sub)
        const syncQuery = `
          UPDATE user_profiles
          SET
            subscription_tier = 'free',
            updated_at = NOW()
          WHERE auth0_sub = $1
        `;

        await client.query(syncQuery, [subscription.user_id]);

        // Commit transaction
        await client.query('COMMIT');

        result.downgraded++;

        logger.info('Grace period expired - downgraded to free', {
          subscriptionId: subscription.id,
          userId: subscription.user_id,
          previousTier: subscription.tier,
        });

        // Send tier change notification (after transaction committed)
        if (notificationsService && subscription.user_email) {
          try {
            const userEmail = subscription.notification_email || subscription.user_email;
            const userName = subscription.display_name || subscription.user_email.split('@')[0];

            await notificationsService.sendTierChangeNotification(
              subscription.user_id,
              userEmail,
              userName,
              subscription.tier,
              'free',
              'grace_period_expiration'
            );

            logger.info('Grace period expiration notification sent', {
              userId: subscription.user_id,
              previousTier: subscription.tier,
            });
          } catch (notifyError: any) {
            // Log but don't fail the job - notification is non-critical
            logger.error('Failed to send grace period expiration notification', {
              userId: subscription.user_id,
              error: notifyError.message,
            });
          }
        }
      } catch (error: any) {
        // Rollback transaction on error
        await client.query('ROLLBACK');

        const errorMsg = `Failed to downgrade subscription ${subscription.id}: ${error.message}`;
        result.errors.push(errorMsg);

        logger.error('Failed to process grace period expiration', {
          subscriptionId: subscription.id,
          userId: subscription.user_id,
          error: error.message,
        });
      }
    }

    logger.info('Grace period expiration job completed', {
      processed: result.processed,
      downgraded: result.downgraded,
      errors: result.errors.length,
    });
  } catch (error: any) {
    logger.error('Grace period job failed', {
      error: error.message,
    });
    throw error;
  } finally {
    client.release();
  }

  return result;
}
