import * as plugins from '../plugins.js';
import { Cloudly } from '../classes.cloudly.js';
import { Cluster } from '../manager.cluster/classes.cluster.js';
import { Server } from './classes.server.js';
import { CurlFresh } from './classes.curlfresh.js';

export class CloudlyServerManager {
  public cloudlyRef: Cloudly;
  public typedRouter = new plugins.typedrequest.TypedRouter();
  public curlfreshInstance = new CurlFresh(this);

  public hetznerAccount: plugins.hetznercloud.HetznerAccount;

  public get db() {
    return this.cloudlyRef.mongodbConnector.smartdataDb;
  }
  public CServer = plugins.smartdata.setDefaultManagerForDoc(this, Server);

  constructor(cloudlyRefArg: Cloudly) {
    this.cloudlyRef = cloudlyRefArg;

    /**
     * is used be serverconfig module on the server to get the actual server config
     */
    this.typedRouter.addTypedHandler(
      new plugins.typedrequest.TypedHandler<plugins.servezoneInterfaces.requests.config.IRequest_Any_Cloudly_GetServerConfig>(
        'getServerConfig',
        async (requestData) => {
          const serverId = requestData.serverId;
          const server = await this.CServer.getInstance({
            id: serverId,
          });
          return {
            configData: await server.createSavableObject(),
          };
        },
      ),
    );
  }

  public async start() {
    this.hetznerAccount = new plugins.hetznercloud.HetznerAccount(
      this.cloudlyRef.config.data.hetznerToken,
    );
  }

  public async stop() {}

  /**
   * creates the server infrastructure on hetzner
   * ensures that there are exactly the reources that are needed
   * no more, no less
   */
  public async ensureServerInfrastructure() {
    // get all clusters
    const allClusters = await this.cloudlyRef.clusterManager.getAllClusters();
    for (const cluster of allClusters) {
      // get existing servers
      const servers = await this.getServersByCluster(cluster);

      // if there is no server, create one
      if (servers.length === 0) {
        const server = await this.hetznerAccount.createServer({
          name: plugins.smartunique.uniSimple('server'),
          location: 'nbg1',
          type: 'cpx41',
          labels: {
            clusterId: cluster.id,
            priority: '1',
          },
          userData: await this.curlfreshInstance.getServerUserData(),
        });
        const newServer = await Server.createFromHetznerServer(server);
        console.log(`cluster created new server for cluster ${cluster.id}`);
      } else {
        console.log(
          `cluster ${cluster.id} already has servers. Making sure that they actually exist in the real world...`,
        );
        // if there is a server, make sure that it exists
        for (const server of servers) {
          const hetznerServer = await this.hetznerAccount.getServersByLabel({
            clusterId: cluster.id,
          });
          if (!hetznerServer) {
            console.log(`server ${server.id} does not exist in the real world. Creating it now...`);
            const hetznerServer = await this.hetznerAccount.createServer({
              name: plugins.smartunique.uniSimple('server'),
              location: 'nbg1',
              type: 'cpx41',
              labels: {
                clusterId: cluster.id,
                priority: '1',
              },
            });
            const newServer = await Server.createFromHetznerServer(hetznerServer);
          }
        }
      }
    }
  }

  public async getServersByCluster(clusterArg: Cluster) {
    const results = await this.CServer.getInstances({
      data: {
        assignedClusterId: clusterArg.id,
      },
    });
    return results;
  }
}