"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
var ScalewayVpcAdapter_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ScalewayVpcAdapter = void 0;
const common_1 = require("@nestjs/common");
const vpc_1 = require("./generated/vpc");
const private_network_1 = require("./generated/private-network");
const cloud_provider_enum_1 = require("../../enums/cloud-provider.enum");
const scaleway_iam_adapter_1 = require("./scaleway-iam.adapter");
let ScalewayVpcAdapter = ScalewayVpcAdapter_1 = class ScalewayVpcAdapter {
    constructor(credentialProvider, iamAdapter) {
        this.credentialProvider = credentialProvider;
        this.iamAdapter = iamAdapter;
        this.logger = new common_1.Logger(ScalewayVpcAdapter_1.name);
    }
    // ─── VNet ID helpers ─────────────────────────────────────────────────────────
    /** Encode region + private network UUID into a Flui vnetId */
    buildVnetId(region, privateNetworkId) {
        return `${region}:${privateNetworkId}`;
    }
    /** Decode a Flui vnetId back to { region, id } */
    parseVnetId(vnetId) {
        const colonIdx = vnetId.indexOf(':');
        if (colonIdx === -1) {
            return { region: 'fr-par', id: vnetId };
        }
        return {
            region: vnetId.substring(0, colonIdx),
            id: vnetId.substring(colonIdx + 1),
        };
    }
    /** Derive region from a Scaleway zone (e.g. 'fr-par-1' → 'fr-par') */
    zoneToRegion(zone) {
        const parts = zone.split('-');
        // e.g. 'fr-par-1' → ['fr','par','1'] → 'fr-par'
        // e.g. 'nl-ams-1' → ['nl','ams','1'] → 'nl-ams'
        // e.g. 'pl-waw-2' → ['pl','waw','2'] → 'pl-waw'
        if (parts.length >= 3) {
            return `${parts[0]}-${parts[1]}`;
        }
        return zone;
    }
    // ─── API factories ───────────────────────────────────────────────────────────
    async createPrivateNetworksApi() {
        const token = await this.credentialProvider.getActiveApiToken(cloud_provider_enum_1.CloudProvider.SCALEWAY);
        return new vpc_1.PrivateNetworksApi(new vpc_1.Configuration({
            baseOptions: { headers: { 'X-Auth-Token': token } },
        }));
    }
    async createSubnetsApi() {
        const token = await this.credentialProvider.getActiveApiToken(cloud_provider_enum_1.CloudProvider.SCALEWAY);
        return new vpc_1.SubnetsApi(new vpc_1.Configuration({
            baseOptions: { headers: { 'X-Auth-Token': token } },
        }));
    }
    async createBaremetalPrivateNetworksApi() {
        const token = await this.credentialProvider.getActiveApiToken(cloud_provider_enum_1.CloudProvider.SCALEWAY);
        return new private_network_1.PrivateNetworksApi(new vpc_1.Configuration({
            baseOptions: { headers: { 'X-Auth-Token': token } },
        }));
    }
    // ─── Private Network (VNet) operations ──────────────────────────────────────
    async createPrivateNetwork(region, name, tags, subnets) {
        const projectId = await this.iamAdapter.getDefaultProjectId();
        this.logger.log(`Creating Scaleway private network: name=${name} region=${region} project_id=${projectId} subnets=${JSON.stringify(subnets)}`);
        const api = await this.createPrivateNetworksApi();
        let resp;
        try {
            resp = await api.createPrivateNetwork(region, { name, project_id: projectId, tags, subnets });
        }
        catch (err) {
            const status = err?.response?.status;
            const detail = err?.response?.data ?? err?.message;
            this.logger.error(`Scaleway createPrivateNetwork failed: status=${status} detail=${JSON.stringify(detail)}`);
            throw err;
        }
        const pn = resp.data;
        const ipRange = pn.subnets?.[0]?.subnet ?? subnets[0] ?? '';
        this.logger.log(`Scaleway private network created: id=${pn.id} region=${region} ipRange=${ipRange}`);
        return {
            vnetId: this.buildVnetId(region, pn.id ?? ''),
            ipRange,
            subnets: (pn.subnets ?? []).map((s) => ({
                ipRange: s.subnet ?? '',
                type: 'cloud',
                networkZone: region,
            })),
        };
    }
    async deletePrivateNetwork(region, privateNetworkId) {
        const api = await this.createPrivateNetworksApi();
        await api.deletePrivateNetwork(region, privateNetworkId);
    }
    async getPrivateNetwork(region, privateNetworkId) {
        try {
            const api = await this.createPrivateNetworksApi();
            const resp = await api.getPrivateNetwork(region, privateNetworkId);
            return this.mapPrivateNetwork(resp.data);
        }
        catch (e) {
            if (e.response?.status === 404)
                return null;
            throw e;
        }
    }
    async listPrivateNetworks(region) {
        const api = await this.createPrivateNetworksApi();
        const resp = await api.listPrivateNetworks(region);
        return (resp.data.private_networks ?? []).map((pn) => this.mapPrivateNetwork(pn));
    }
    // ─── Subnet operations ───────────────────────────────────────────────────────
    async addSubnets(region, privateNetworkId, subnets) {
        const api = await this.createSubnetsApi();
        await api.addSubnets(region, privateNetworkId, {
            subnets,
        });
    }
    async deleteSubnets(region, privateNetworkId, subnets) {
        const api = await this.createSubnetsApi();
        await api.deleteSubnets(region, privateNetworkId, { subnets });
    }
    // ─── Server attachment (Elastic Metal only) ──────────────────────────────────
    async attachBaremetalToPrivateNetwork(zone, serverId, privateNetworkId) {
        const api = await this.createBaremetalPrivateNetworksApi();
        await api.addServerPrivateNetwork(zone, serverId, { private_network_id: privateNetworkId });
        this.logger.log(`Elastic Metal server ${serverId} attached to private network ${privateNetworkId} in zone ${zone}`);
    }
    async detachBaremetalFromPrivateNetwork(zone, serverId, privateNetworkId) {
        const api = await this.createBaremetalPrivateNetworksApi();
        await api.deleteServerPrivateNetwork(zone, serverId, privateNetworkId);
        this.logger.log(`Elastic Metal server ${serverId} detached from private network ${privateNetworkId} in zone ${zone}`);
    }
    // ─── Mapping helpers ─────────────────────────────────────────────────────────
    mapPrivateNetwork(pn) {
        const region = pn.region ?? 'fr-par';
        const subnets = (pn.subnets ?? []).map((s) => ({
            id: s.id,
            ipRange: s.subnet ?? '',
            type: 'cloud',
            networkZone: region,
        }));
        return {
            id: this.buildVnetId(region, pn.id ?? ''),
            name: pn.name ?? '',
            ipRange: pn.subnets?.[0]?.subnet ?? '',
            subnets,
            routes: [],
            attachedServerIds: [],
            labels: (pn.tags ?? []).reduce((acc, tag) => {
                const eqIdx = tag.indexOf('=');
                if (eqIdx === -1) {
                    acc[tag] = '';
                }
                else {
                    acc[tag.substring(0, eqIdx)] = tag.substring(eqIdx + 1);
                }
                return acc;
            }, {}),
            created: pn.created_at,
        };
    }
};
exports.ScalewayVpcAdapter = ScalewayVpcAdapter;
exports.ScalewayVpcAdapter = ScalewayVpcAdapter = ScalewayVpcAdapter_1 = __decorate([
    (0, common_1.Injectable)(),
    __param(0, (0, common_1.Inject)('ICredentialProvider')),
    __metadata("design:paramtypes", [Object, scaleway_iam_adapter_1.ScalewayIamAdapter])
], ScalewayVpcAdapter);
