import { XMLParser } from "fast-xml-parser";
import { Resource } from "../../resource.js";
import { ignore } from "../../util/ignore.js";
import { logger } from "../../util/logger.js";
import { mergeTimeoutConfig, waitForResourceState, } from "../../util/timeout.js";
import { callEC2Api, createEC2Client } from "./utils.js";
/**
 * Wait for Internet Gateway to be in available state
 */
async function waitForInternetGatewayAvailable(client, internetGatewayId, timeoutConfig) {
    const checkFunction = async () => {
        const response = await callEC2Api(client, "DescribeInternetGateways", parseInternetGatewayXmlResponse, {
            "InternetGatewayId.1": internetGatewayId,
        });
        return response.InternetGateways?.[0];
    };
    const isReady = (igw) => {
        return igw?.State === "available" || igw !== undefined; // IGWs are usually immediately available
    };
    await waitForResourceState(checkFunction, isReady, timeoutConfig, internetGatewayId, "Internet Gateway", "is now available");
}
/**
 * Wait for Internet Gateway to be deleted
 */
async function waitForInternetGatewayDeleted(client, internetGatewayId, timeoutConfig) {
    const checkFunction = async () => {
        try {
            const response = await callEC2Api(client, "DescribeInternetGateways", parseInternetGatewayXmlResponse, {
                "InternetGatewayId.1": internetGatewayId,
            });
            return response.InternetGateways?.[0];
        }
        catch (error) {
            // If Internet Gateway is not found, it's been deleted - return undefined
            if (error.code === "InvalidInternetGatewayID.NotFound" ||
                error.code === "InvalidInternetGateway.NotFound") {
                return undefined;
            }
            throw error;
        }
    };
    const isReady = (igw) => {
        // Internet Gateway is deleted if it doesn't exist
        return !igw;
    };
    await waitForResourceState(checkFunction, isReady, timeoutConfig, internetGatewayId, "Internet Gateway", "deletion completed");
}
/**
 * AWS Internet Gateway Resource
 *
 * An Internet Gateway is a horizontally scaled, redundant, and highly available VPC component
 * that allows communication between your VPC and the internet. It serves two purposes:
 * 1. Provide a target in your VPC route tables for internet-routable traffic
 * 2. Perform network address translation (NAT) for instances with public IPv4 addresses
 *
 * Supports AWS credential overrides at the resource level, allowing you to deploy Internet Gateways
 * to different AWS accounts or regions than the default scope configuration.
 *
 * @example
 * ```typescript
 * // Create a basic Internet Gateway
 * const igw = await InternetGateway("main-igw", {
 *   tags: {
 *     Name: "main-internet-gateway",
 *     Environment: "production"
 *   }
 * });
 * ```
 *
 * @example
 * ```typescript
 * // Create Internet Gateway with AWS credential overrides
 * const crossAccountIgw = await InternetGateway("cross-account-igw", {
 *   // Override AWS credentials for this specific resource
 *   region: "us-east-1",
 *   profile: "production-account",
 *   tags: {
 *     Name: "cross-account-internet-gateway",
 *     Environment: "production"
 *   }
 * });
 * ```
 *
 * @example
 * ```typescript
 * // Create Internet Gateway in different region with role assumption
 * const multiRegionIgw = await InternetGateway("multi-region-igw", {
 *   region: "eu-west-1",
 *   roleArn: "arn:aws:iam::123456789012:role/CrossRegionRole",
 *   roleSessionName: "internet-gateway-deployment",
 *   tags: {
 *     Name: "eu-internet-gateway",
 *     Region: "europe"
 *   }
 * });
 * ```
 *
 * @example
 * ```typescript
 * // Create Internet Gateway with explicit credentials
 * const explicitCredsIgw = await InternetGateway("explicit-creds-igw", {
 *   accessKeyId: alchemy.secret("AKIAIOSFODNN7EXAMPLE"),
 *   secretAccessKey: alchemy.secret("wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"),
 *   region: "us-west-2",
 *   tags: {
 *     Name: "explicit-credentials-igw",
 *     Purpose: "testing"
 *   }
 * });
 * ```
 *
 * @example
 * ```typescript
 * // Create Internet Gateway with custom timeout configuration
 * const customIgw = await InternetGateway("custom-igw", {
 *   timeout: {
 *     maxAttempts: 90,
 *     delayMs: 1500
 *   },
 *   tags: {
 *     Name: "custom-timeout-igw",
 *     Purpose: "high-availability"
 *   }
 * });
 * ```
 *
 * @example
 * ```typescript
 * // Create Internet Gateway and attach to VPC
 * const vpc = await VPC("main-vpc", { cidrBlock: "10.0.0.0/16" });
 * const igw = await InternetGateway("vpc-igw", {
 *   tags: { Name: "vpc-internet-gateway" }
 * });
 * const attachment = await InternetGatewayAttachment("igw-attachment", {
 *   internetGatewayId: igw.internetGatewayId,
 *   vpcId: vpc.vpcId
 * });
 * ```
 *
 * @example
 * ```typescript
 * // Multi-account deployment with scope-level and resource-level overrides
 * await alchemy.run("production", {
 *   aws: { region: "us-west-2", profile: "main-account" }
 * }, async () => {
 *   // This IGW uses scope credentials (main-account, us-west-2)
 *   const mainIgw = await InternetGateway("main-igw", {
 *     tags: { Name: "main-account-igw" }
 *   });
 *
 *   // This IGW overrides to use different account
 *   const crossAccountIgw = await InternetGateway("cross-account-igw", {
 *     profile: "secondary-account",
 *     region: "us-east-1", // Also override region
 *     tags: { Name: "secondary-account-igw" }
 *   });
 * });
 * ```
 */
export const InternetGateway = Resource("aws::InternetGateway", async function (_id, props) {
    // Create EC2 client with credential resolution handled internally
    const client = await createEC2Client(props);
    const timeoutConfig = mergeTimeoutConfig(INTERNET_GATEWAY_TIMEOUT, props.timeout);
    if (this.phase === "delete") {
        if (this.output?.internetGatewayId) {
            logger.log(`🗑️ Deleting Internet Gateway: ${this.output.internetGatewayId}`);
            // Simply delete the Internet Gateway - attachments should handle themselves
            await ignore("InvalidInternetGatewayID.NotFound", async () => {
                await callEC2Api(client, "DeleteInternetGateway", parseInternetGatewayXmlResponse, {
                    InternetGatewayId: this.output.internetGatewayId,
                });
            });
            // Wait for Internet Gateway to be fully deleted
            await waitForInternetGatewayDeleted(client, this.output.internetGatewayId, timeoutConfig);
            logger.log(`  ✅ Internet Gateway ${this.output.internetGatewayId} deletion completed`);
        }
        return this.destroy();
    }
    let internetGateway;
    if (this.phase === "update" && this.output?.internetGatewayId) {
        // Get existing Internet Gateway
        const response = await callEC2Api(client, "DescribeInternetGateways", parseInternetGatewayXmlResponse, {
            "InternetGatewayId.1": this.output.internetGatewayId,
        });
        if (!response.InternetGateways?.[0]) {
            throw new Error(`Internet Gateway ${this.output.internetGatewayId} not found`);
        }
        internetGateway = response.InternetGateways[0];
    }
    else {
        // Create new Internet Gateway
        const createInternetGatewayParams = {};
        // Add tags if provided
        if (props.tags) {
            createInternetGatewayParams.TagSpecifications = [
                {
                    ResourceType: "internet-gateway",
                    Tags: Object.entries(props.tags).map(([key, value]) => ({
                        Key: key,
                        Value: value,
                    })),
                },
            ];
        }
        const createParams = convertCreateInternetGatewayParamsToAwsFormat(createInternetGatewayParams);
        const response = await callEC2Api(client, "CreateInternetGateway", parseInternetGatewayXmlResponse, createParams);
        if (!response.InternetGateway) {
            throw new Error("Failed to create Internet Gateway");
        }
        internetGateway = response.InternetGateway;
        // Wait for Internet Gateway to be available
        await waitForInternetGatewayAvailable(client, internetGateway.InternetGatewayId, timeoutConfig);
    }
    return {
        internetGatewayId: internetGateway.InternetGatewayId,
        state: "available",
        attachments: internetGateway.Attachments?.map((att) => ({
            vpcId: att.VpcId,
            state: att.State,
        })),
        ownerId: internetGateway.OwnerId,
        ...props,
    };
});
/**
 * Internet Gateway timeout constants
 */
export const INTERNET_GATEWAY_TIMEOUT = {
    maxAttempts: 60,
    delayMs: 2000, // 2 seconds - IGWs are medium speed resources
};
/**
 * Helper functions to convert typed parameters to AWS API format
 */
function convertCreateInternetGatewayParamsToAwsFormat(params) {
    const awsParams = {};
    if (params.DryRun !== undefined) {
        awsParams.DryRun = params.DryRun.toString();
    }
    // Handle TagSpecifications
    if (params.TagSpecifications) {
        params.TagSpecifications.forEach((tagSpec, specIndex) => {
            const specNum = specIndex + 1;
            awsParams[`TagSpecification.${specNum}.ResourceType`] =
                tagSpec.ResourceType;
            tagSpec.Tags.forEach((tag, tagIndex) => {
                const tagNum = tagIndex + 1;
                awsParams[`TagSpecification.${specNum}.Tag.${tagNum}.Key`] = tag.Key;
                awsParams[`TagSpecification.${specNum}.Tag.${tagNum}.Value`] =
                    tag.Value;
            });
        });
    }
    return awsParams;
}
/**
 * Parse XML responses specifically for Internet Gateway operations
 */
function parseInternetGatewayXmlResponse(xmlText) {
    const parser = new XMLParser({
        ignoreAttributes: true,
        parseAttributeValue: true,
        parseTagValue: true,
        trimValues: true,
    });
    const parsed = parser.parse(xmlText);
    const result = {};
    // Parse CreateInternetGatewayResponse
    if (parsed.CreateInternetGatewayResponse) {
        const internetGateway = parsed.CreateInternetGatewayResponse
            .internetGateway;
        if (internetGateway) {
            result.InternetGateway = {
                InternetGatewayId: internetGateway.internetGatewayId,
                State: "available", // Internet Gateways are immediately available
                Attachments: internetGateway.attachmentSet?.item
                    ? (Array.isArray(internetGateway.attachmentSet.item)
                        ? internetGateway.attachmentSet.item
                        : [internetGateway.attachmentSet.item]).map((attachment) => ({
                        VpcId: attachment.vpcId,
                        State: attachment.state,
                    }))
                    : [],
                Tags: internetGateway.tagSet?.item
                    ? Array.isArray(internetGateway.tagSet.item)
                        ? internetGateway.tagSet.item.map((tag) => ({
                            Key: tag.key,
                            Value: tag.value,
                        }))
                        : [
                            {
                                Key: internetGateway.tagSet.item.key,
                                Value: internetGateway.tagSet.item.value,
                            },
                        ]
                    : undefined,
                OwnerId: internetGateway.ownerId,
            };
        }
    }
    // Parse DescribeInternetGatewaysResponse
    if (parsed.DescribeInternetGatewaysResponse) {
        const internetGatewaySet = parsed.DescribeInternetGatewaysResponse.internetGatewaySet;
        if (internetGatewaySet?.item) {
            const igws = Array.isArray(internetGatewaySet.item)
                ? internetGatewaySet.item
                : [internetGatewaySet.item];
            result.InternetGateways = igws.map((igw) => ({
                InternetGatewayId: igw.internetGatewayId,
                State: "available",
                Attachments: igw.attachmentSet?.item
                    ? (Array.isArray(igw.attachmentSet.item)
                        ? igw.attachmentSet.item
                        : [igw.attachmentSet.item]).map((attachment) => ({
                        VpcId: attachment.vpcId,
                        State: attachment.state,
                    }))
                    : [],
                Tags: igw.tagSet?.item
                    ? Array.isArray(igw.tagSet.item)
                        ? igw.tagSet.item.map((tag) => ({ Key: tag.key, Value: tag.value }))
                        : [{ Key: igw.tagSet.item.key, Value: igw.tagSet.item.value }]
                    : undefined,
                OwnerId: igw.ownerId,
            }));
        }
        else {
            result.InternetGateways = [];
        }
    }
    // Handle success responses
    if (parsed.AttachInternetGatewayResponse ||
        parsed.DetachInternetGatewayResponse ||
        parsed.DeleteInternetGatewayResponse) {
        result.success = true;
    }
    return result;
}
//# sourceMappingURL=internet-gateway.js.map