import config from "../config.ts";
import axios from "axios";
import { VMManager, type VM } from "./base.ts";

const SCW_SECRET_KEY = config.SCW_SECRET_KEY;
const SCW_ORGANIZATION_ID = config.SCW_ORGANIZATION_ID;
const region = "nl-ams-1"; //fr-par-1
const gatewayHost = config.SCW_GATEWAY;

export class Scaleway extends VMManager {
  size = "DEV1-S"; // DEV1-S, DEV1-M, DEV1-L, GP1-XS
  largeSize = "DEV1-M";
  minRetries = 5;
  reuseVMs = true;
  id = "Scaleway";
  imageId = config.SCW_IMAGE;
  startVM = async (name: string) => {
    const response = await axios({
      method: "POST",
      url: `https://api.scaleway.com/instance/v1/zones/${region}/servers`,
      headers: {
        "X-Auth-Token": SCW_SECRET_KEY,
        "Content-Type": "application/json",
      },
      data: {
        name: name,
        dynamic_ip_required: true,
        commercial_type: this.isLarge ? this.largeSize : this.size,
        image: this.imageId,
        volumes: {},
        organization: SCW_ORGANIZATION_ID,
        tags: [this.getTag()],
      },
    });
    // console.log(response.data);
    const id = response.data.server.id;
    const response2 = await axios({
      method: "PATCH",
      url: `https://api.scaleway.com/instance/v1/zones/${region}/servers/${id}/user_data/cloud-init`,
      headers: {
        "X-Auth-Token": SCW_SECRET_KEY,
        "Content-Type": "text/plain",
      },
      // set userdata for boot action
      //data: cloudInit(),
    });
    // console.log(response2.data);
    // boot the instance
    const response3 = await axios({
      method: "POST",
      url: `https://api.scaleway.com/instance/v1/zones/${region}/servers/${id}/action`,
      headers: {
        "X-Auth-Token": SCW_SECRET_KEY,
        "Content-Type": "application/json",
      },
      data: {
        action: "poweron",
      },
    });
    // console.log(response3.data);
    return id;
  };

  terminateVM = async (id: string) => {
    const response = await axios({
      method: "POST",
      url: `https://api.scaleway.com/instance/v1/zones/${region}/servers/${id}/action`,
      headers: {
        "X-Auth-Token": SCW_SECRET_KEY,
        "Content-Type": "application/json",
      },
      data: {
        action: "terminate",
      },
    });
  };

  rebootVM = async (id: string) => {
    // Reboot the VM (also destroys the Docker container since it has --rm flag)
    const response2 = await axios({
      method: "POST",
      url: `https://api.scaleway.com/instance/v1/zones/${region}/servers/${id}/action`,
      headers: {
        "X-Auth-Token": SCW_SECRET_KEY,
        "Content-Type": "application/json",
      },
      data: {
        action: "reboot",
      },
    });
    return;
  };

  reimageVM = async (id: string) => {
    // Scaleway doesn't have a reimage/rebuild command. Delete the VM
    await this.terminateVMWrapper(id);
  };

  getVM = async (id: string) => {
    const response = await axios({
      method: "GET",
      url: `https://api.scaleway.com/instance/v1/zones/${region}/servers/${id}`,
      headers: {
        "X-Auth-Token": SCW_SECRET_KEY,
        "Content-Type": "application/json",
      },
    });
    let server = this.mapServerObject(response.data.server);
    return server;
  };

  listVMs = async (filter: string) => {
    const limit = this.getLimitSize();
    const pageCount = Math.ceil((limit || 1) / 100);
    const pages = Array.from(Array(pageCount).keys()).map((i) => i + 1);
    const responses: any[] = await Promise.all(
      pages.map((page) =>
        axios({
          method: "GET",
          url: `https://api.scaleway.com/instance/v1/zones/${region}/servers`,
          headers: {
            "X-Auth-Token": SCW_SECRET_KEY,
            "Content-Type": "application/json",
          },
          params: {
            page,
            per_page: 100,
            tags: filter,
          },
        }),
      ),
    );
    const responsesMapped = responses.map((response) =>
      response.data.servers.map(this.mapServerObject),
    );
    return responsesMapped.flat();
  };

  powerOn = async (_id: string) => {};

  attachToNetwork = async (_id: string) => {};

  updateSnapshot = async () => {
    return "";
  };

  mapServerObject = (server: any): VM => {
    // const ip = server.private_ip;
    const ip = server.public_ip?.address;
    return {
      id: server.id,
      // The gateway handles SSL termination and proxies to the private IP
      host: ip ? `${gatewayHost}/?ip=${ip}` : "",
      provider: this.id,
      large: this.isLarge,
      region: this.region,
    };
  };
}
