import * as cdk from "aws-cdk-lib";
import { execSync } from "child_process";
import "source-map-support/register";
import { AcmUsEast1Stack } from "../lib/acm-us-east-1-stack";
import { AuthStack } from "../lib/auth-stack";
import { BackupStack } from "../lib/backup-stack";
import { ClientApiStack } from "../lib/client-api-stack";
import { COST_DISTRIBUTION_TAG_KEY } from "../lib/const";
import { context } from "../lib/context";
import { ContractApiStack } from "../lib/contract-api-stack";
import { DBStack } from "../lib/db-stack";
import { DomainStack } from "../lib/domain-stack";
import { FrontendStack } from "../lib/frontend-stack";
import { LogDeliveryUsEast1Stack } from "../lib/log-delivery-us-east-1-stack";
import { ManagementApiStack } from "../lib/management-api-stack";
import { NetworkStack } from "../lib/network-stack";
import { StorageStack } from "../lib/storage-stack";
import { ToolStack } from "../lib/tool-stack";

const app = new cdk.App();
const commitSha = execSync("git rev-parse HEAD").toString().trim();
const stage = app.node.tryGetContext("stage");
const { domainProps, networkProps, authProps, dbProps, apiProps, backupProps, frontendProps } =
  context[stage] || context.dev;

cdk.Tags.of(app).add(COST_DISTRIBUTION_TAG_KEY, stage);

const domain = new DomainStack(app, "DomainStack", {
  stackName: `${stage}-domain-stack`,
  stage,
  domainProps,
  env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
  crossRegionReferences: true,
});

const network = new NetworkStack(app, "NetworkStack", {
  stackName: `${stage}-network-stack`,
  stage,
  networkProps: networkProps,
  env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
});

const acmUsEast1 = new AcmUsEast1Stack(app, "AcmUsEast1Stack", {
  stackName: `${stage}-acm-us-east-1-stack`,
  stage,
  hostedZone: domain.hostedZone,
  enableUserPoolCustomDomain: authProps.enableUserPoolCustomDomain,
  env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: "us-east-1" },
  crossRegionReferences: true,
});

const db = new DBStack(app, "DbStack", {
  stackName: `${stage}-db-stack`,
  stage,
  dbProps,
  vpc: network.vpc,
  env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
});

const auth = new AuthStack(app, "AuthStack", {
  stackName: `${stage}-auth-stack`,
  stage,
  authProps,
  vpc: network.vpc,
  hostedZone: domain.hostedZone,
  managementM2MCertificate: acmUsEast1.userPoolCertificate,
  managementUserCertificate: acmUsEast1.managementUserCertificate,
  contractUserPoolCertificate: acmUsEast1.contractUserPoolCertificate,
  env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
  crossRegionReferences: true,
});

auth.addDependency(db);

const storage = new StorageStack(app, "StorageStack", {
  stackName: `${stage}-storage-stack`,
  stage,
  env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
});

const managementApi = new ManagementApiStack(app, "ManagementApiStack", {
  stackName: `${stage}-management-api-stack`,
  stage,
  apiProps,
  vpc: network.vpc,
  env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
});
managementApi.addDependency(domain);
managementApi.addDependency(auth);
managementApi.addDependency(db);

const clientApi = new ClientApiStack(app, "ClientApiStack", {
  stackName: `${stage}-client-api-stack`,
  stage,
  apiProps,
  vpc: network.vpc,
  env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
});
clientApi.addDependency(domain);
clientApi.addDependency(db);
clientApi.addDependency(storage);

const contractApi = new ContractApiStack(app, "ContractApiStack", {
  stackName: `${stage}-contract-api-stack`,
  stage,
  apiProps,
  vpc: network.vpc,
  env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
});
contractApi.addDependency(domain);
contractApi.addDependency(auth);
contractApi.addDependency(db);

const tool = new ToolStack(app, "ToolStack", {
  stackName: `${stage}-tool-stack`,
  stage,
  commitSha: commitSha,
  vpc: network.vpc,
  env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
});
tool.addDependency(db);

new BackupStack(app, "BackupStack", {
  stackName: `${stage}-backup-stack`,
  stage,
  backupProps,
  env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
});

const frontend = new FrontendStack(app, "FrontendStack", {
  stackName: `${stage}-frontend-stack`,
  stage,
  frontendProps,
  certificate: acmUsEast1.managementConsoleCertificate,
  env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: process.env.CDK_DEFAULT_REGION },
  crossRegionReferences: true,
});
frontend.addDependency(domain);
frontend.addDependency(auth);
frontend.addDependency(managementApi);

const logDelivery = new LogDeliveryUsEast1Stack(app, "LogDeliveryUsEast1Stack", {
  stackName: `${stage}-log-delivery-us-east-1-stack`,
  stage,
  enableFrontendAccessLog: frontendProps.enableAccessLog,
  managementConsoleDistributionArn: frontend.managementConsoleDistribution.distributionArn,
  managementConsoleLogBucketArn: frontend.managementConsoleLogBucket?.bucketArn,
  env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: "us-east-1" },
  crossRegionReferences: true,
});
logDelivery.addDependency(frontend);
