import { App, Tags } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import 'source-map-support/register';
import { Environment } from '../shared/environment';
import { ExampleStack, ExampleStackProps } from './example-stack';
import { toValidTag } from './to-valid-tag';

export const createApp = (): App => {
  /*
    The AWS CDK team recommends to declare all stacks of all environments in the source code (Model all production stages in code - https://docs.aws.amazon.com/cdk/v2/guide/best-practices.html#best-practices-apps).
    This guide explains the approach in more detail (https://taimos.de/blog/deploying-your-cdk-app-to-different-stages-and-environments).
    Environment variables are used to fixate the account and region at synthesis time (https://docs.aws.amazon.com/cdk/v2/guide/environments.html).
    They can be set via the '.env' file or via the shell in use.
  */

  const app = new App();
  const serviceName = '<%= projectName %>';
<% environments.forEach((environment) => { %>
  const <%= environment.toLowerCase() %>Account =
    process.env['CDK_<%= environment.toUpperCase() %>_ACCOUNT'] ?? process.env['CDK_DEFAULT_ACCOUNT'];
  if (!<%= environment.toLowerCase() %>Account) {
    throw new Error(
      `The <%= environment %> account isn't defined. Please set it via the '.env' file in the project directory.`,
    );
  }

  const <%= environment.toLowerCase() %>Region =
    process.env['CDK_<%= environment.toUpperCase() %>_REGION'] ?? process.env['CDK_DEFAULT_REGION'];
  if (!<%= environment.toLowerCase() %>Region) {
    throw new Error(
      `The <%= environment %> region isn't defined. Please set it via the '.env' file in the project directory.`,
    );
  }

  new EnvironmentStacks(app, Environment.<%= environment %>, {
    environment: Environment.<%= environment %>,
    serviceName,
    env: {
      account: <%= environment.toLowerCase() %>Account,
      region: <%= environment.toLowerCase() %>Region,
    },
  });
<% }); %>

  return app;
};

export interface EnvironmentStacksProps extends ExampleStackProps {
  environment: Environment;
  serviceName: string;
}

export class EnvironmentStacks extends Construct {
  constructor(scope: Construct, id: string, props: EnvironmentStacksProps) {
    const { environment, serviceName, ...stackProps } = props;

    super(scope, id);

    const exampleStack = new ExampleStack(this, `${serviceName.slice(0,1).toUpperCase()}${serviceName.slice(1)}`, stackProps);

    Tags.of(exampleStack).add('Environment', toValidTag(environment));
    Tags.of(exampleStack).add('App', toValidTag(serviceName));
  }
}
