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";
/**
 * AWS Route Table Resource
 *
 * Creates and manages route tables that control the routing of network traffic
 * within a VPC. Route tables contain rules (routes) that determine where network
 * traffic is directed. Subnet associations are managed separately using the
 * RouteTableAssociation resource.
 *
 * Supports AWS credential overrides at the resource level, allowing you to deploy Route Tables
 * to different AWS accounts or regions than the default scope configuration.
 *
 * @example
 * // Create a basic route table
 * const routeTable = await RouteTable("main-route-table", {
 *   vpc: myVpc,
 *   tags: {
 *     Name: "main-route-table",
 *     Environment: "production"
 *   }
 * });
 *
 * @example
 * // Create a public route table for internet access
 * const publicRouteTable = await RouteTable("public-routes", {
 *   vpc: myVpc,
 *   tags: {
 *     Name: "public-route-table",
 *     Type: "public",
 *     Purpose: "internet-access"
 *   }
 * });
 *
 * @example
 * // Create Route Table with AWS credential overrides
 * const crossAccountRouteTable = await RouteTable("cross-account-rt", {
 *   vpc: mainVpc,
 *   // Override AWS credentials for this specific resource
 *   region: "us-east-1",
 *   profile: "production-account",
 *   tags: {
 *     Name: "cross-account-route-table",
 *     Environment: "production"
 *   }
 * });
 *
 * @example
 * // Create Route Table in different region with role assumption
 * const multiRegionRouteTable = await RouteTable("multi-region-rt", {
 *   vpc: euVpc,
 *   region: "eu-west-1",
 *   roleArn: "arn:aws:iam::123456789012:role/CrossRegionRole",
 *   roleSessionName: "route-table-deployment",
 *   tags: {
 *     Name: "eu-route-table",
 *     Region: "europe"
 *   }
 * });
 *
 * @example
 * // Create Route Table with explicit credentials
 * const explicitCredsRouteTable = await RouteTable("explicit-creds-rt", {
 *   vpc: testVpc,
 *   accessKeyId: alchemy.secret("AKIAIOSFODNN7EXAMPLE"),
 *   secretAccessKey: alchemy.secret("wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"),
 *   region: "us-west-2",
 *   tags: {
 *     Name: "explicit-credentials-rt",
 *     Purpose: "testing"
 *   }
 * });
 *
 * @example
 * // Create a private route table for internal traffic
 * const privateRouteTable = await RouteTable("private-routes", {
 *   vpc: myVpc,
 *   tags: {
 *     Name: "private-route-table",
 *     Type: "private",
 *     Purpose: "internal-only"
 *   }
 * });
 *
 * @example
 * // Create a route table with custom timeout configuration
 * const customRouteTable = await RouteTable("custom-routes", {
 *   vpc: myVpc,
 *   timeout: {
 *     maxAttempts: 45,
 *     delayMs: 1500
 *   },
 *   tags: {
 *     Name: "custom-timeout-route-table"
 *   }
 * });
 *
 * @example
 * // Multi-account deployment with scope-level and resource-level overrides
 * await alchemy.run("production", {
 *   aws: { region: "us-west-2", profile: "main-account" }
 * }, async () => {
 *   // This Route Table uses scope credentials (main-account, us-west-2)
 *   const mainRouteTable = await RouteTable("main-rt", {
 *     vpc: mainVpc,
 *     tags: { Name: "main-account-rt" }
 *   });
 *
 *   // This Route Table overrides to use different account
 *   const crossAccountRouteTable = await RouteTable("cross-account-rt", {
 *     vpc: crossVpc,
 *     profile: "secondary-account",
 *     region: "us-east-1", // Also override region
 *     tags: { Name: "secondary-account-rt" }
 *   });
 * });
 */
export const RouteTable = Resource("aws::RouteTable", async function (_id, props) {
    // Create EC2 client with credential resolution handled internally
    const client = await createEC2Client(props);
    const timeoutConfig = mergeTimeoutConfig(ROUTE_TABLE_TIMEOUT, props.timeout);
    const vpcId = typeof props.vpc === "string" ? props.vpc : props.vpc.vpcId;
    if (this.phase === "delete") {
        if (this.output?.routeTableId) {
            logger.log(`🗑️ Deleting Route Table: ${this.output.routeTableId}`);
            // Delete the Route Table
            await ignore("InvalidRouteTableID.NotFound", async () => {
                await callEC2Api(client, "DeleteRouteTable", parseRouteTableXmlResponse, {
                    RouteTableId: this.output.routeTableId,
                });
            });
            // Wait for Route Table to be fully deleted
            await waitForRouteTableDeleted(client, this.output.routeTableId, timeoutConfig);
            logger.log(`  ✅ Route Table ${this.output.routeTableId} deletion completed`);
        }
        return this.destroy();
    }
    let routeTable;
    if (this.phase === "update" && this.output?.routeTableId) {
        logger.log(`🔄 Updating Route Table: ${this.output.routeTableId}`);
        // Get existing route table
        const response = await callEC2Api(client, "DescribeRouteTables", parseRouteTableXmlResponse, {
            "RouteTableId.1": this.output.routeTableId,
        });
        if (!response.RouteTables?.[0]) {
            throw new Error(`Route Table ${this.output.routeTableId} not found`);
        }
        routeTable = response.RouteTables[0];
        logger.log(`  ✅ Route Table ${this.output.routeTableId} updated`);
    }
    else {
        logger.log(`🚀 Creating Route Table in VPC ${vpcId}`);
        // Create new route table
        const createRouteTableParams = {
            VpcId: vpcId,
        };
        // Add tags if specified
        if (props.tags) {
            createRouteTableParams.TagSpecifications = [
                {
                    ResourceType: "route-table",
                    Tags: Object.entries(props.tags).map(([key, value]) => ({
                        Key: key,
                        Value: value,
                    })),
                },
            ];
        }
        const createParams = convertCreateRouteTableParamsToAwsFormat(createRouteTableParams);
        const response = await callEC2Api(client, "CreateRouteTable", parseRouteTableXmlResponse, createParams);
        if (!response.RouteTable) {
            throw new Error("Failed to create route table");
        }
        routeTable = response.RouteTable;
        logger.log(`  ✅ Route Table ${routeTable.RouteTableId} created`);
    }
    return {
        routeTableId: routeTable.RouteTableId,
        vpcId: routeTable.VpcId,
        ...props,
        vpc: vpcId,
    };
});
/**
 * Route Table timeout constants
 */
export const ROUTE_TABLE_TIMEOUT = {
    maxAttempts: 30,
    delayMs: 1000, // 1 second - Route Tables are fast resources
};
/**
 * Helper functions to convert typed parameters to AWS API format
 */
function convertCreateRouteTableParamsToAwsFormat(params) {
    const awsParams = {
        VpcId: params.VpcId,
    };
    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 Route Table operations
 */
function parseRouteTableXmlResponse(xmlText) {
    const parser = new XMLParser({
        ignoreAttributes: true,
        parseAttributeValue: true,
        parseTagValue: true,
        trimValues: true,
    });
    const parsed = parser.parse(xmlText);
    const result = {};
    // Parse CreateRouteTableResponse
    if (parsed.CreateRouteTableResponse) {
        const routeTable = parsed.CreateRouteTableResponse
            .routeTable;
        if (routeTable) {
            result.RouteTable = {
                RouteTableId: routeTable.routeTableId,
                VpcId: routeTable.vpcId,
                Routes: routeTable.routeSet?.item
                    ? (Array.isArray(routeTable.routeSet.item)
                        ? routeTable.routeSet.item
                        : [routeTable.routeSet.item]).map((route) => ({
                        DestinationCidrBlock: route.destinationCidrBlock,
                        GatewayId: route.gatewayId,
                        InstanceId: route.instanceId,
                        NatGatewayId: route.natGatewayId,
                        State: route.state,
                        Origin: route.origin,
                    }))
                    : [],
            };
        }
    }
    // Parse DescribeRouteTablesResponse
    if (parsed.DescribeRouteTablesResponse) {
        const routeTableSet = parsed.DescribeRouteTablesResponse.routeTableSet;
        if (routeTableSet?.item) {
            const routeTables = Array.isArray(routeTableSet.item)
                ? routeTableSet.item
                : [routeTableSet.item];
            result.RouteTables = routeTables.map((routeTable) => ({
                RouteTableId: routeTable.routeTableId,
                VpcId: routeTable.vpcId,
                Routes: routeTable.routeSet?.item
                    ? (Array.isArray(routeTable.routeSet.item)
                        ? routeTable.routeSet.item
                        : [routeTable.routeSet.item]).map((route) => ({
                        DestinationCidrBlock: route.destinationCidrBlock,
                        GatewayId: route.gatewayId,
                        InstanceId: route.instanceId,
                        NatGatewayId: route.natGatewayId,
                        State: route.state,
                        Origin: route.origin,
                    }))
                    : [],
            }));
        }
        else {
            result.RouteTables = [];
        }
    }
    // Handle success responses
    if (parsed.DeleteRouteTableResponse) {
        result.success = true;
    }
    return result;
}
/**
 * Wait for Route Table to be deleted
 */
async function waitForRouteTableDeleted(client, routeTableId, timeoutConfig) {
    const checkFunction = async () => {
        try {
            const response = await callEC2Api(client, "DescribeRouteTables", parseRouteTableXmlResponse, {
                "RouteTableId.1": routeTableId,
            });
            return response.RouteTables?.[0];
        }
        catch (error) {
            // If Route Table is not found, it's been deleted - return undefined
            if (error.code === "InvalidRouteTableID.NotFound" ||
                error.code === "InvalidRouteTable.NotFound") {
                return undefined;
            }
            throw error;
        }
    };
    const isReady = (rt) => {
        // Route Table is deleted if it doesn't exist
        return !rt;
    };
    await waitForResourceState(checkFunction, isReady, timeoutConfig, routeTableId, "Route Table", "be deleted");
}
//# sourceMappingURL=route-table.js.map