import {
  SESv2Client,
  CreateEmailIdentityCommand,
  GetEmailIdentityCommand,
  PutEmailIdentityMailFromAttributesCommand,
  DeleteEmailIdentityCommand,
  BehaviorOnMxFailure,
  AlreadyExistsException,
  NotFoundException,
} from "@aws-sdk/client-sesv2";

import { env } from "@/config/env";
import {
  SesIdentityProvider,
  SesIdentityResult,
  SesIdentityStatus,
  SesVerificationStatus,
} from "./ses-identity-provider";

let sharedClient: SESv2Client | null = null;

function getClient(): SESv2Client {
  if (!sharedClient) {
    sharedClient = new SESv2Client({
      region: env.awsRegion,
      credentials:
        env.awsAccessKeyId && env.awsSecretAccessKey
          ? { accessKeyId: env.awsAccessKeyId, secretAccessKey: env.awsSecretAccessKey }
          : undefined,
    });
  }
  return sharedClient;
}

function mapStatus(verifiedForSending: boolean | undefined, dkimStatus: string | undefined): SesVerificationStatus {
  if (verifiedForSending && dkimStatus === "SUCCESS") return "VERIFIED";
  if (dkimStatus === "FAILED") return "FAILED";
  return "PENDING";
}

export class SesIdentityProviderImpl implements SesIdentityProvider {
  async createIdentity(domain: string): Promise<SesIdentityResult> {
    try {
      const response = await getClient().send(
        new CreateEmailIdentityCommand({ EmailIdentity: domain })
      );

      return {
        dkimTokens: response.DkimAttributes?.Tokens ?? [],
      };
    } catch (error) {
      if (error instanceof AlreadyExistsException) {
        const existing = await getClient().send(new GetEmailIdentityCommand({ EmailIdentity: domain }));
        return { dkimTokens: existing.DkimAttributes?.Tokens ?? [] };
      }
      throw error;
    }
  }

  async putMailFromAttributes(domain: string, mailFromDomain: string): Promise<void> {
    await getClient().send(
      new PutEmailIdentityMailFromAttributesCommand({
        EmailIdentity: domain,
        MailFromDomain: mailFromDomain,
        BehaviorOnMxFailure: BehaviorOnMxFailure.USE_DEFAULT_VALUE,
      })
    );
  }

  async getIdentity(domain: string): Promise<SesIdentityStatus> {
    const response = await getClient().send(new GetEmailIdentityCommand({ EmailIdentity: domain }));

    return {
      verificationStatus: mapStatus(response.VerifiedForSendingStatus, response.DkimAttributes?.Status),
      dkimTokens: response.DkimAttributes?.Tokens ?? [],
    };
  }

  async deleteIdentity(domain: string): Promise<void> {
    try {
      await getClient().send(new DeleteEmailIdentityCommand({ EmailIdentity: domain }));
    } catch (error) {
      if (error instanceof NotFoundException) return;
      throw error;
    }
  }
}
