import * as command from '@pulumi/command';
import * as digitalocean from '@pulumi/digitalocean';
import * as hcloud from '@pulumi/hcloud';
import * as pulumi from '@pulumi/pulumi';
import * as tls from '@pulumi/tls';
import * as fs from 'fs';

const config = new pulumi.Config();
const hcloudToken = config.getSecret('hcloudToken');

if (hcloudToken === undefined) {
  throw new Error('Hetzner Cloud token was not set');
}

const provider = new hcloud.Provider('provider', {
  token: hcloudToken,
});

const sshKey = new tls.PrivateKey('sshKey', {
  algorithm: 'ED25519',
});

export const privateKey = sshKey.privateKeyOpenssh;

const env = pulumi.getStack();

if (!fs.existsSync(`./.local/${env}`)) {
  fs.mkdirSync(`./.local/${env}`);
}
privateKey.apply((privKey) =>
  fs.writeFileSync(`./.local/${env}/private_key`, privKey, { mode: '0600' })
);

const hetznerSshKey = new hcloud.SshKey(
  'iac_default',
  {
    publicKey: sshKey.publicKeyOpenssh,
  },
  { provider }
);

export const swarmMaster = await createSwarmCluster(1);

async function createSwarmCluster(nodeCount: number) {
  const dockerImage = await hcloud.getImage(
    {
      name: 'docker-ce',
      withArchitecture: 'x86',
    },
    { provider }
  );

  const swarmNet = new hcloud.Network(
    'swarm-net',
    {
      ipRange: '172.16.0.0/16',
    },
    { provider }
  );

  const swarmSubNet = new hcloud.NetworkSubnet(
    'swarm-subnet-dev',
    {
      networkId: swarmNet.id.apply((id) => +id),
      type: 'cloud',
      networkZone: 'eu-central',
      ipRange: '172.16.1.0/24',
    },
    { provider }
  );

  const vm = new hcloud.Server(
    `node-1`,
    {
      sshKeys: [hetznerSshKey.id],
      serverType: 'ccx23',
      location: 'fsn1',
      image: `${dockerImage.id}`,
      labels: { nodeType: 'dockerSwarmNode' },
    },
    { provider }
  );
  const srvNet = new hcloud.ServerNetwork(
    'node_1-net',
    {
      serverId: vm.id.apply((id) => +id),
      networkId: swarmNet.id.apply((id) => +id),
      ip: '172.16.1.1',
    },
    { provider }
  );
  const swarmInit = vm.id.apply((id) => {
    return new command.remote.Command(
      `dockerSwarmInit-${id}`,
      {
        connection: {
          host: vm.ipv4Address,
          user: 'root',
          privateKey: privateKey,
        },
        create: [
          'docker swarm init --advertise-addr 172.16.1.1',
          'echo "Manager Token: $(docker swarm join-token -q manager)"',
          'echo "Worker Token: $(docker swarm join-token -q worker)"',
        ].join('&&'),
      },
      { dependsOn: [vm] }
    );
  });

  const swarmTokens = {
    worker: '',
    manager: '',
  };

  swarmInit.stdout.apply((output) => {
    const managerToken = output.match(/Manager Token: (\S+)/)?.[1];
    const workerToken = output.match(/Worker Token: (\S+)/)?.[1];

    if (managerToken && workerToken) {
      swarmTokens.manager = managerToken;
      swarmTokens.worker = workerToken;
    }
  });

  // for (let i = 1; i < nodeCount; i++) {
  //   const node = new hcloud.Server(
  //     `node-${i + 1}`,
  //     {
  //       sshKeys: [hetznerSshKey.id],
  //       serverType: 'cx21',
  //       location: 'fsn1',
  //       image: `${dockerImage.id}`,
  //       labels: { nodeType: 'dockerSwarmNode' },
  //       userData: cloudConfig.then((cc) => cc.rendered),
  //     },
  //     { provider, dependsOn: [swarmInit] }
  //   );

  //   const srvNet = new hcloud.ServerNetwork(
  //     `node_${i + 1}-net`,
  //     {
  //       serverId: node.id.apply((id) => +id),
  //       networkId: swarmNet.id.apply((id) => +id),
  //       ip: `172.16.1.${i + 1}`,
  //     },
  //     { provider }
  //   );

  //   const swarmJoin = node.id.apply((id) => {
  //     return new command.remote.Command(
  //       `dockerSwarmInit-${id}`,
  //       {
  //         connection: {
  //           host: node.ipv4Address,
  //           user: 'root',
  //           privateKey: privateKey,
  //         },
  //         create: vm.ipv4Address.apply(
  //           (ip) =>
  //             `docker swarm join --token ${swarmTokens.worker} 172.16.1.1:2377`
  //         ),
  //       },
  //       { dependsOn: [node] }
  //     );
  //   });
  // }
  return vm;
}

const doToken = config.getSecret('doToken');
if (doToken) {
  const geniusceo = digitalocean.Domain.get('geniusceo', 'genius.ceo');

  const wwwSubDomain = geniusceo.id.apply(
    (id) =>
      new digitalocean.DnsRecord('www', {
        domain: id,
        type: 'A',
        value: swarmMaster.ipv4Address,
        name: 'www',
      })
  );

  const noSubDomain = geniusceo.id.apply(
    (id) =>
      new digitalocean.DnsRecord('noSub', {
        domain: id,
        type: 'A',
        value: swarmMaster.ipv4Address,
        name: '@',
      })
  );

  const wildcardSubDomain = geniusceo.id.apply(
    (id) =>
      new digitalocean.DnsRecord('*', {
        domain: id,
        type: 'A',
        value: swarmMaster.ipv4Address,
        name: '*',
      })
  );
}

const installAnsibleDepsCmd = new command.remote.Command(
  'installAnsibleDepsCmd',
  {
    connection: {
      host: swarmMaster.ipv4Address,
      user: 'root',
      privateKey: privateKey,
    },
    create: `apt-get update && apt-get install -y python3-pip python3-jsondiff`,
  }
);

const deployDockerStackCmd = new command.local.Command(
  'deployDockerStackCmd',
  {
    create: pulumi.interpolate`ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -u root -i "${swarmMaster.ipv4Address}," --private-key ./.local/${env}/private_key ansible/playbook.yml`,
  },
  {
    dependsOn: [installAnsibleDepsCmd],
  }
);

const restartCmd = new command.remote.Command(
  'restartCmd',
  {
    connection: {
      host: swarmMaster.ipv4Address,
      user: 'root',
      privateKey: privateKey,
    },
    create: `shutdown -r 0`,
  },
  {
    dependsOn: [deployDockerStackCmd],
  }
);
