const {
  SchedulerClient,
  CreateScheduleCommand,
  DeleteScheduleCommand,
} = require("@aws-sdk/client-scheduler");
const { getAWSConfig } = require("../config/aws");
const logger = require("../utils/logger");

/**
 * Service for managing EventBridge Scheduler schedules for condition check reminders.
 *
 * Creates one-time schedules when a rental is confirmed:
 * - pre_rental_owner: 24 hours before rental start
 * - rental_start_renter: At rental start
 * - rental_end_renter: At rental end
 * - post_rental_owner: 24 hours after rental end
 */
class EventBridgeSchedulerService {
  constructor() {
    if (EventBridgeSchedulerService.instance) {
      return EventBridgeSchedulerService.instance;
    }

    this.client = null;
    this.initialized = false;
    // Only enable when explicitly set - allows deploying code without activating the feature
    this.conditionCheckRemindersEnabled =
      process.env.CONDITION_CHECK_REMINDERS_ENABLED === "true";

    EventBridgeSchedulerService.instance = this;
  }

  /**
   * Initialize the EventBridge Scheduler client.
   */
  async initialize() {
    if (this.initialized) return;

    try {
      const awsConfig = getAWSConfig();
      this.client = new SchedulerClient(awsConfig);
      this.initialized = true;
      logger.info("EventBridge Scheduler Service initialized");
    } catch (error) {
      logger.error("Failed to initialize EventBridge Scheduler Service", {
        error,
      });
      throw error;
    }
  }

  /**
   * Get configuration from environment.
   */
  getConfig() {
    return {
      groupName:
        process.env.SCHEDULER_GROUP_NAME || "condition-check-reminders",
      lambdaArn: process.env.LAMBDA_CONDITION_CHECK_ARN,
      schedulerRoleArn: process.env.SCHEDULER_ROLE_ARN,
    };
  }

  /**
   * Create schedule name for a rental and check type.
   */
  getScheduleName(rentalId, checkType) {
    return `rental-${rentalId}-${checkType}`;
  }

  /**
   * Calculate schedule times for all 4 check types.
   */
  getScheduleTimes(rental) {
    const startDate = new Date(rental.startDateTime);
    const endDate = new Date(rental.endDateTime);

    return {
      pre_rental_owner: new Date(startDate.getTime() - 24 * 60 * 60 * 1000),
      rental_start_renter: startDate,
      rental_end_renter: endDate,
      post_rental_owner: new Date(endDate.getTime() + 24 * 60 * 60 * 1000),
    };
  }

  /**
   * Create a single EventBridge schedule.
   */
  async createSchedule(name, scheduleTime, payload) {
    if (!this.initialized) {
      await this.initialize();
    }

    const config = this.getConfig();

    if (!config.lambdaArn) {
      logger.warn("Lambda ARN not configured, skipping schedule creation", {
        name,
      });
      return null;
    }

    // Don't create schedules for times in the past
    if (scheduleTime <= new Date()) {
      logger.info("Schedule time is in the past, skipping", {
        name,
        scheduleTime,
      });
      return null;
    }

    try {
      const command = new CreateScheduleCommand({
        Name: name,
        GroupName: config.groupName,
        ScheduleExpression: `at(${scheduleTime.toISOString().replace(".000Z", "")})`,
        ScheduleExpressionTimezone: "UTC",
        FlexibleTimeWindow: {
          Mode: "OFF",
        },
        Target: {
          Arn: config.lambdaArn,
          RoleArn: config.schedulerRoleArn,
          Input: JSON.stringify({
            ...payload,
            scheduleName: name,
          }),
        },
        ActionAfterCompletion: "DELETE", // Auto-delete after execution
      });

      const result = await this.client.send(command);

      logger.info("Created EventBridge schedule", {
        name,
        scheduleTime,
        scheduleArn: result.ScheduleArn,
      });

      return result.ScheduleArn;
    } catch (error) {
      // If schedule already exists, that's okay
      if (error.name === "ConflictException") {
        logger.info("Schedule already exists", { name });
        return name;
      }

      logger.error("Failed to create EventBridge schedule", {
        name,
        error: error.message,
      });
      throw error;
    }
  }

  /**
   * Delete a single EventBridge schedule.
   */
  async deleteSchedule(name) {
    if (!this.initialized) {
      await this.initialize();
    }

    const config = this.getConfig();

    try {
      const command = new DeleteScheduleCommand({
        Name: name,
        GroupName: config.groupName,
      });

      await this.client.send(command);

      logger.info("Deleted EventBridge schedule", { name });
      return true;
    } catch (error) {
      // If schedule doesn't exist, that's okay
      if (error.name === "ResourceNotFoundException") {
        logger.info("Schedule not found (already deleted)", { name });
        return true;
      }

      logger.error("Failed to delete EventBridge schedule", {
        name,
        error: error.message,
      });
      throw error;
    }
  }

  /**
   * Create all 4 condition check schedules for a rental.
   * Call this after a rental is confirmed.
   */
  async createConditionCheckSchedules(rental) {
    if (!this.conditionCheckRemindersEnabled) {
      logger.debug(
        "EventBridge Scheduler disabled, skipping schedule creation"
      );
      return null;
    }

    logger.info("Creating condition check schedules for rental", {
      rentalId: rental.id,
    });

    const scheduleTimes = this.getScheduleTimes(rental);
    let schedulesCreated = 0;

    const checkTypes = [
      "pre_rental_owner",
      "rental_start_renter",
      "rental_end_renter",
      "post_rental_owner",
    ];

    for (const checkType of checkTypes) {
      const name = this.getScheduleName(rental.id, checkType);
      const scheduleTime = scheduleTimes[checkType];

      try {
        const arn = await this.createSchedule(name, scheduleTime, {
          rentalId: rental.id,
          checkType,
          scheduledFor: scheduleTime.toISOString(),
        });

        if (arn) {
          schedulesCreated++;
        }
      } catch (error) {
        logger.error("Failed to create schedule, continuing with others", {
          rentalId: rental.id,
          checkType,
          error: error.message,
        });
      }
    }

    logger.info("Finished creating condition check schedules", {
      rentalId: rental.id,
      schedulesCreated,
    });

    return schedulesCreated;
  }

  /**
   * Delete all condition check schedules for a rental.
   * Call this when a rental is cancelled.
   */
  async deleteConditionCheckSchedules(rental) {
    if (!this.conditionCheckRemindersEnabled) {
      logger.debug(
        "EventBridge Scheduler disabled, skipping schedule deletion"
      );
      return;
    }

    logger.info("Deleting condition check schedules for rental", {
      rentalId: rental.id,
    });

    const checkTypes = [
      "pre_rental_owner",
      "rental_start_renter",
      "rental_end_renter",
      "post_rental_owner",
    ];

    for (const checkType of checkTypes) {
      const name = this.getScheduleName(rental.id, checkType);

      try {
        await this.deleteSchedule(name);
      } catch (error) {
        logger.error("Failed to delete schedule, continuing with others", {
          rentalId: rental.id,
          checkType,
          error: error.message,
        });
      }
    }

    logger.info("Finished deleting condition check schedules", {
      rentalId: rental.id,
    });
  }
}

// Export singleton instance
module.exports = new EventBridgeSchedulerService();
