"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
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 __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
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 HetznerCapabilitiesService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.HetznerCapabilitiesService = void 0;
const fs = __importStar(require("node:fs"));
const path = __importStar(require("node:path"));
const common_1 = require("@nestjs/common");
const config_1 = require("@nestjs/config");
const credentials_entity_1 = require("../../../management/entities/credentials.entity");
const cloud_provider_enum_1 = require("../../enums/cloud-provider.enum");
const generated_1 = require("../../../../modules/providers/implementations/hetzner/generated");
const region_coordinates_1 = require("../../data/region-coordinates");
let HetznerCapabilitiesService = HetznerCapabilitiesService_1 = class HetznerCapabilitiesService {
    constructor(configService, credentialProvider) {
        this.configService = configService;
        this.credentialProvider = credentialProvider;
        this.logger = new common_1.Logger(HetznerCapabilitiesService_1.name);
        this.basePath = this.configService.get('HETZNER_API_BASE_PATH', 'https://api.hetzner.cloud/v1');
    }
    async getAvailableRegions() {
        this.logger.log('Fetching available regions from Hetzner API');
        try {
            const token = await this.credentialProvider.getActiveApiToken(cloud_provider_enum_1.CloudProvider.HETZNER);
            const configuration = new generated_1.Configuration({
                accessToken: token,
                basePath: this.basePath,
            });
            const locationsApi = new generated_1.LocationsApi(configuration);
            const response = await locationsApi.listLocations();
            this.logger.log(`Fetched ${response.data.locations.length} locations from Hetzner`);
            return this.mapHetznerLocationsToRegions(response.data.locations);
        }
        catch (error) {
            this.logger.error('Failed to fetch regions from Hetzner API', error);
            this.logger.warn('Using fallback mock data for regions');
            return this.getMockRegions();
        }
    }
    async getSupportedInstanceTypes() {
        this.logger.log('Fetching supported instance types from Hetzner API');
        try {
            const token = await this.credentialProvider.getActiveApiToken(cloud_provider_enum_1.CloudProvider.HETZNER);
            const configuration = new generated_1.Configuration({
                accessToken: token,
                basePath: this.basePath,
            });
            const serverTypesApi = new generated_1.ServerTypesApi(configuration);
            const response = await serverTypesApi.listServerTypes();
            this.logger.log(`Fetched ${response.data.server_types.length} server types from Hetzner`);
            return this.mapHetznerServerTypesToInstanceTypes(response.data.server_types);
        }
        catch (error) {
            this.logger.error('Failed to fetch instance types from Hetzner API', error);
            this.logger.warn('Using fallback mock data for instance types');
            return this.getMockInstanceTypes();
        }
    }
    async getProviderInfo() {
        return {
            id: cloud_provider_enum_1.CloudProvider.HETZNER,
            name: 'hetzner',
            displayName: 'Hetzner Cloud',
            description: 'German cloud provider with excellent price/performance ratio',
            logoUrl: '/api/v1/management/providers/hetzner/logo',
            websiteUrl: 'https://www.hetzner.com/cloud',
            documentationUrl: 'https://docs.hetzner.cloud/',
            supportUrl: 'https://community.hetzner.com/',
            accessKeyDocumentationUrl: 'https://docs.hetzner.com/cloud/api/getting-started/generating-api-token/',
            pricingUrl: 'https://www.hetzner.com/cloud#pricing',
            credentialFields: {
                type: credentials_entity_1.CredentialType.API_KEY,
                supportsExpiry: true,
                fields: [
                    {
                        key: 'apiKey',
                        label: 'API Token',
                        providerLabel: 'API Token',
                        hint: 'Hetzner Cloud Console → Security → API Tokens → Generate API Token',
                        secret: true,
                        required: true,
                    },
                ],
            },
            dnsZoneDelegation: {
                nameservers: [
                    'ns1.your-server.de',
                    'ns.second-ns.com',
                    'ns3.second-ns.de',
                ],
                delegationGuideUrl: 'https://docs.hetzner.com/networking/dns/getting-started/delegate-to-hetzner/',
            },
        };
    }
    getLogo() {
        return fs.readFileSync(HetznerCapabilitiesService_1.LOGO_PATH);
    }
    getLogoContentType() {
        return 'image/svg+xml';
    }
    async validateCredentials(credentials) {
        if (credentials.type !== credentials_entity_1.CredentialType.API_KEY || !credentials.apiKey) {
            return {
                success: false,
                message: 'An API token is required for Hetzner',
            };
        }
        try {
            const configuration = new generated_1.Configuration({
                accessToken: credentials.apiKey,
                basePath: this.basePath,
            });
            const locationsApi = new generated_1.LocationsApi(configuration);
            await locationsApi.listLocations();
            return { success: true, message: 'API token is valid' };
        }
        catch (error) {
            if (error.response?.status === 401) {
                return { success: false, message: 'Invalid API token' };
            }
            this.logger.error('Hetzner credential validation failed', error.message);
            return { success: false, message: 'Validation failed: ' + error.message };
        }
    }
    async getCapabilities() {
        const [regions, instanceTypes] = await Promise.all([
            this.getAvailableRegions(),
            this.getSupportedInstanceTypes(),
        ]);
        return {
            ...this.getStaticCapabilities(),
            supportedInstanceTypes: instanceTypes.map((type) => type.id),
            supportedRegions: regions,
        };
    }
    getStaticCapabilities() {
        return {
            supportedInstanceTypes: [],
            supportedRegions: [],
            credentialType: 'api_key',
            features: {
                autoScaling: false,
                loadBalancers: true,
                privateNetworking: true,
                snapshots: true,
                backups: true,
                dnsZones: true,
                nodeProvisioning: true,
            },
            pricing: {
                currency: 'EUR',
                billingCycle: 'hourly',
                minimumCost: 0.0056, // CX23: 2 vCPU, 4 GB RAM @ €2.99/mo
            },
            // Hetzner private networks are ZONE-SCOPED: a single VNet is tied to exactly one
            // network zone. Servers within the same zone (e.g. fsn1/nbg1/hel1 all share
            // eu-central) can join the same VNet. Cross-zone communication is not possible
            // over private networks. Subnets within a VNet are further scoped by zone.
            // Only eu-central is in scope for Flui — us-east/us-west/ap-southeast excluded.
            // Ref: https://docs.hetzner.com/networking/networks/faq/
            vnetTopology: {
                scope: 'regional',
                zones: [
                    {
                        id: 'eu-central',
                        displayName: 'Europe (Central)',
                        coveredRegions: ['fsn1', 'nbg1', 'hel1'],
                    },
                ],
                supportsSubnets: true,
                subnetPerZone: true,
                supportsRoutes: true,
                // Hetzner accepts /8–/29 for both VNet and subnets
                // Ref: https://docs.hetzner.com/cloud/networks/overview/
                vnetIpRange: { minPrefix: 8, maxPrefix: 29 },
                subnetIpRange: { minPrefix: 8, maxPrefix: 29 },
            },
        };
    }
    mapHetznerLocationsToRegions(locations) {
        return locations
            .filter((location) => this.isEuropeanLocation(location))
            .map((location) => {
            const coords = (0, region_coordinates_1.getRegionCoordinates)(cloud_provider_enum_1.CloudProvider.HETZNER, location.name);
            return {
                id: location.name,
                name: location.city,
                displayName: location.city,
                location: location.country,
                available: true,
                flagEmoji: this.getCountryFlag(location.country),
                country: location.country,
                latitude: coords?.latitude,
                longitude: coords?.longitude,
            };
        });
    }
    isEuropeanLocation(location) {
        if (location.network_zone === 'eu-central') {
            return true;
        }
        const europeanCountries = [
            'DE',
            'FI',
            'NL',
            'AT',
            'BE',
            'FR',
            'IT',
            'ES',
            'PL',
            'CZ',
            'SE',
            'NO',
            'DK',
            'CH',
            'GB',
            'IE',
            'PT',
        ];
        return europeanCountries.includes(location.country);
    }
    mapHetznerServerTypesToInstanceTypes(serverTypes) {
        return serverTypes
            .filter((type) => !type.deprecated)
            .map((type) => {
            const defaultPrice = type.prices && type.prices.length > 0 ? type.prices[0] : null;
            return {
                id: type.name,
                name: type.name.toUpperCase(),
                description: type.description,
                cpu: type.cores,
                memory: type.memory * 1024,
                disk: type.disk * 1024,
                bandwidth: 20000,
                pricing: {
                    hourly: defaultPrice
                        ? Number.parseFloat(defaultPrice.price_hourly?.net || '0')
                        : 0,
                    monthly: defaultPrice
                        ? Number.parseFloat(defaultPrice.price_monthly?.net || '0')
                        : 0,
                    currency: 'EUR',
                },
                available: !type.deprecated,
            };
        });
    }
    getCountryFlag(country) {
        const flags = {
            Germany: '🇩🇪',
            Finland: '🇫🇮',
            USA: '🇺🇸',
            'United States': '🇺🇸',
            Netherlands: '🇳🇱',
            Singapore: '🇸🇬',
        };
        return flags[country] || '🌐';
    }
    getMockRegions() {
        const make = (id, name, country, flagEmoji) => {
            const coords = (0, region_coordinates_1.getRegionCoordinates)(cloud_provider_enum_1.CloudProvider.HETZNER, id);
            return {
                id,
                name,
                displayName: `${name}, ${country}`,
                location: country,
                available: true,
                flagEmoji,
                country,
                latitude: coords?.latitude,
                longitude: coords?.longitude,
            };
        };
        return [
            make('fsn1', 'Falkenstein', 'Germany', '🇩🇪'),
            make('nbg1', 'Nuremberg', 'Germany', '🇩🇪'),
            make('hel1', 'Helsinki', 'Finland', '🇫🇮'),
        ];
    }
    getMockInstanceTypes() {
        // Instances with ≥ 4 GB RAM suitable for observability workloads
        return [
            {
                id: 'cx23',
                name: 'CX23',
                description: '2 vCPU (shared Intel/AMD), 4 GB RAM, 40 GB NVMe',
                cpu: 2,
                memory: 4096,
                disk: 40960,
                bandwidth: 20000,
                pricing: { hourly: 0.0056, monthly: 2.99, currency: 'EUR' },
                available: true,
            },
            {
                id: 'cx33',
                name: 'CX33',
                description: '4 vCPU (shared Intel/AMD), 8 GB RAM, 80 GB NVMe',
                cpu: 4,
                memory: 8192,
                disk: 81920,
                bandwidth: 20000,
                pricing: { hourly: 0.0099, monthly: 5.99, currency: 'EUR' },
                available: true,
            },
            {
                id: 'cx43',
                name: 'CX43',
                description: '8 vCPU (shared Intel/AMD), 16 GB RAM, 160 GB NVMe',
                cpu: 8,
                memory: 16384,
                disk: 163840,
                bandwidth: 20000,
                pricing: { hourly: 0.0193, monthly: 11.99, currency: 'EUR' },
                available: true,
            },
            {
                id: 'cax11',
                name: 'CAX11',
                description: '2 vCPU (ARM Ampere), 4 GB RAM, 40 GB NVMe',
                cpu: 2,
                memory: 4096,
                disk: 40960,
                bandwidth: 20000,
                pricing: { hourly: 0.0061, monthly: 3.29, currency: 'EUR' },
                available: true,
            },
            {
                id: 'cax21',
                name: 'CAX21',
                description: '4 vCPU (ARM Ampere), 8 GB RAM, 80 GB NVMe',
                cpu: 4,
                memory: 8192,
                disk: 81920,
                bandwidth: 20000,
                pricing: { hourly: 0.0112, monthly: 6.49, currency: 'EUR' },
                available: true,
            },
        ];
    }
};
exports.HetznerCapabilitiesService = HetznerCapabilitiesService;
HetznerCapabilitiesService.LOGO_PATH = path.resolve(process.cwd(), 'dist/modules/providers/implementations/hetzner/assets/logo.svg');
exports.HetznerCapabilitiesService = HetznerCapabilitiesService = HetznerCapabilitiesService_1 = __decorate([
    (0, common_1.Injectable)(),
    __param(1, (0, common_1.Inject)('ICredentialProvider')),
    __metadata("design:paramtypes", [config_1.ConfigService, Object])
], HetznerCapabilitiesService);
