#!/usr/bin/env node

import { Command } from 'commander';
import { resolve as dnsResolve } from 'dns/promises';
import { createLambdaClient, invokeLambda, InvokePayload, LambdaResponse } from './invoke';
import { STSClient, GetCallerIdentityCommand } from '@aws-sdk/client-sts';

/**
 * Parses and retrieves command-line arguments.
 */
const program = new Command();

program
  .name('ip-whitelist-cli')
  .description('CLI tool to update IP whitelist via AWS Lambda')
  .version('1.0.0')
  .option('-p, --profile <profile>', 'AWS profile to use')
  .option('-r, --region <region>', 'AWS region', 'us-east-1')
  .parse(process.argv);

const options = program.opts();

/**
 * Retrieves the current caller's identity using AWS STS.
 *
 * @param stsClient - An instance of STSClient.
 * @returns The caller's identity.
 */
const getCallerIdentity = async (stsClient: STSClient) => {
  const command = new GetCallerIdentityCommand({});
  try {
    const response = await stsClient.send(command);
    return response;
  } catch (error: any) {
    console.error('Error fetching caller identity:', error.message || error);
    throw error;
  }
};

/**
 * The main function orchestrating the CLI tool's operations.
 */
const main = async () => {
  const { profile, region } = options;

  const lambdaClient = createLambdaClient(region, profile);
  const stsClient = new STSClient({
    region,
    credentials: profile ? undefined : undefined,
  });

  let callerIdentity;
  try {
    callerIdentity = await getCallerIdentity(stsClient);
    const { UserId, Account, Arn } = callerIdentity;
    console.log(`Caller Identity - UserId: ${UserId}, Account: ${Account}, Arn: ${Arn}`);
  } catch (error) {
    process.exit(1);
  }

  const arnParts = callerIdentity.Arn?.split('/') || [];
  const usernameWithDomain = arnParts[arnParts.length - 1];

  if (!usernameWithDomain) {
    console.error('Unable to extract username from ARN.');
    process.exit(1);
  }

  if (!usernameWithDomain.endsWith('@tezda.com')) {
    console.error('Error: Username does not end with @tezda.com');
    process.exit(1);
  }

  const [userPrefix] = usernameWithDomain.split('@');
  if (!userPrefix) {
    console.error('Error extracting username prefix.');
    process.exit(1);
  }

  const constructedHostname = `${userPrefix}-tezda.ddns.net`;
  console.log(`Constructed hostname: ${constructedHostname}`);

  let ipAddress: string;
  try {
    const addresses = await dnsResolve(constructedHostname);
    if (addresses.length === 0) {
      throw new Error(`No IP addresses found for hostname: ${constructedHostname}`);
    }
    ipAddress = addresses[0];
    console.log(`Resolved IP address for ${constructedHostname}: ${ipAddress}`);
  } catch (error: any) {
    console.error('Error resolving hostname:', error.message || error);
    process.exit(1);
  }

  const payload: InvokePayload = {
    ipAddress,
    tag: usernameWithDomain,
  };

  const lambdaFunctionName = 'tezda-ip-whitelist-cli-dev-updateIp';

  try {
    await invokeLambda(lambdaClient, lambdaFunctionName, payload);
  } catch (error: any) {
    console.error('Failed to invoke Lambda function:', error.message || error);
    process.exit(1);
  }
};

main();
