import * as cdk from "aws-cdk-lib";
import * as lambda from "aws-cdk-lib/aws-lambda";
import * as iam from "aws-cdk-lib/aws-iam";
import * as scheduler from "aws-cdk-lib/aws-scheduler";
import * as sqs from "aws-cdk-lib/aws-sqs";
import { Construct } from "constructs";
import * as path from "path";

interface ConditionCheckLambdaStackProps extends cdk.StackProps {
  /**
   * Environment name (staging, prod)
   */
  environment: string;

  /**
   * Database URL for the Lambda
   */
  databaseUrl: string;

  /**
   * Frontend URL for email links
   */
  frontendUrl: string;

  /**
   * SES sender email
   */
  sesFromEmail: string;

  /**
   * SES sender name
   */
  sesFromName?: string;

  /**
   * Whether emails are enabled
   */
  emailEnabled?: boolean;
}

export class ConditionCheckLambdaStack extends cdk.Stack {
  /**
   * The Lambda function for condition check reminders
   */
  public readonly lambdaFunction: lambda.Function;

  /**
   * The EventBridge Scheduler group for condition check schedules
   */
  public readonly scheduleGroup: scheduler.CfnScheduleGroup;

  /**
   * Dead letter queue for failed Lambda invocations
   */
  public readonly deadLetterQueue: sqs.Queue;

  /**
   * IAM role for EventBridge Scheduler to invoke Lambda
   */
  public readonly schedulerRole: iam.Role;

  constructor(
    scope: Construct,
    id: string,
    props: ConditionCheckLambdaStackProps
  ) {
    super(scope, id, props);

    const {
      environment,
      databaseUrl,
      frontendUrl,
      sesFromEmail,
      sesFromName = "Village Share",
      emailEnabled = true,
    } = props;

    // Dead Letter Queue for failed Lambda invocations
    this.deadLetterQueue = new sqs.Queue(this, "ConditionCheckDLQ", {
      queueName: `condition-check-reminder-dlq-${environment}`,
      retentionPeriod: cdk.Duration.days(14),
    });

    // Lambda execution role
    const lambdaRole = new iam.Role(this, "ConditionCheckLambdaRole", {
      roleName: `condition-check-lambda-role-${environment}`,
      assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
      description: "Execution role for Condition Check Reminder Lambda",
    });

    // CloudWatch Logs permissions
    lambdaRole.addToPolicy(
      new iam.PolicyStatement({
        effect: iam.Effect.ALLOW,
        actions: [
          "logs:CreateLogGroup",
          "logs:CreateLogStream",
          "logs:PutLogEvents",
        ],
        resources: ["*"],
      })
    );

    // SES permissions for sending emails
    lambdaRole.addToPolicy(
      new iam.PolicyStatement({
        effect: iam.Effect.ALLOW,
        actions: ["ses:SendEmail", "ses:SendRawEmail"],
        resources: ["*"],
      })
    );

    // EventBridge Scheduler permissions (for self-cleanup)
    lambdaRole.addToPolicy(
      new iam.PolicyStatement({
        effect: iam.Effect.ALLOW,
        actions: ["scheduler:DeleteSchedule"],
        resources: [
          `arn:aws:scheduler:${this.region}:${this.account}:schedule/condition-check-reminders-${environment}/*`,
        ],
      })
    );

    // Lambda function
    this.lambdaFunction = new lambda.Function(
      this,
      "ConditionCheckReminderLambda",
      {
        functionName: `condition-check-reminder-${environment}`,
        runtime: lambda.Runtime.NODEJS_20_X,
        handler: "index.handler",
        code: lambda.Code.fromAsset(
          path.join(__dirname, "../../../lambdas/conditionCheckReminder"),
          {
            bundling: {
              image: lambda.Runtime.NODEJS_20_X.bundlingImage,
              command: [
                "bash",
                "-c",
                [
                  "cp -r /asset-input/* /asset-output/",
                  "cd /asset-output",
                  "npm install --omit=dev",
                  // Copy shared modules
                  "mkdir -p shared",
                  "cp -r /asset-input/../shared/* shared/",
                  "cd shared && npm install --omit=dev",
                ].join(" && "),
              ],
            },
          }
        ),
        role: lambdaRole,
        timeout: cdk.Duration.seconds(30),
        memorySize: 256,
        environment: {
          NODE_ENV: environment,
          DATABASE_URL: databaseUrl,
          FRONTEND_URL: frontendUrl,
          SES_FROM_EMAIL: sesFromEmail,
          SES_FROM_NAME: sesFromName,
          EMAIL_ENABLED: emailEnabled ? "true" : "false",
          SCHEDULE_GROUP_NAME: `condition-check-reminders-${environment}`,
          AWS_REGION: this.region,
        },
        deadLetterQueue: this.deadLetterQueue,
        retryAttempts: 2,
        description: "Sends condition check reminder emails for rentals",
      }
    );

    // EventBridge Scheduler group
    this.scheduleGroup = new scheduler.CfnScheduleGroup(
      this,
      "ConditionCheckScheduleGroup",
      {
        name: `condition-check-reminders-${environment}`,
      }
    );

    // IAM role for EventBridge Scheduler to invoke Lambda
    this.schedulerRole = new iam.Role(this, "SchedulerRole", {
      roleName: `condition-check-scheduler-role-${environment}`,
      assumedBy: new iam.ServicePrincipal("scheduler.amazonaws.com"),
      description: "Role for EventBridge Scheduler to invoke Lambda",
    });

    // Allow scheduler to invoke the Lambda
    this.schedulerRole.addToPolicy(
      new iam.PolicyStatement({
        effect: iam.Effect.ALLOW,
        actions: ["lambda:InvokeFunction"],
        resources: [
          this.lambdaFunction.functionArn,
          `${this.lambdaFunction.functionArn}:*`,
        ],
      })
    );

    // Outputs
    new cdk.CfnOutput(this, "LambdaFunctionArn", {
      value: this.lambdaFunction.functionArn,
      description: "ARN of the Condition Check Reminder Lambda",
      exportName: `ConditionCheckLambdaArn-${environment}`,
    });

    new cdk.CfnOutput(this, "ScheduleGroupName", {
      value: this.scheduleGroup.name!,
      description: "Name of the EventBridge Scheduler group",
      exportName: `ConditionCheckScheduleGroup-${environment}`,
    });

    new cdk.CfnOutput(this, "SchedulerRoleArn", {
      value: this.schedulerRole.roleArn,
      description: "ARN of the EventBridge Scheduler IAM role",
      exportName: `ConditionCheckSchedulerRoleArn-${environment}`,
    });

    new cdk.CfnOutput(this, "DLQUrl", {
      value: this.deadLetterQueue.queueUrl,
      description: "URL of the Dead Letter Queue",
      exportName: `ConditionCheckDLQUrl-${environment}`,
    });
  }
}
