import config from "../config.ts";
import fs from "node:fs";
import {
  S3Client,
  GetObjectCommand,
  NotFound,
  HeadObjectCommand,
} from "@aws-sdk/client-s3";
import axios from "axios";
import { calendarIdCountMap } from "../state.ts";

const submittedCalendarIds = fs
  .readFileSync("./submitted.txt", "utf8")
  .split("\n")
  .map((id) => id.trim())
  .filter((id) => id !== "");

const shuffledSubmittedCalendarIds = submittedCalendarIds.sort(
  () => Math.random() - 0.5
);

console.log(
  `Read ${shuffledSubmittedCalendarIds.length} submitted calendar IDs`
);

const uniqueSubmittedCalendarIds = new Set(submittedCalendarIds);

console.log(
  `Read ${uniqueSubmittedCalendarIds.size} unique submitted calendar IDs`
);

const s3 = new S3Client({
  region: config.aws.region,
  credentials: {
    accessKeyId: config.aws.accessKeyId,
    secretAccessKey: config.aws.secretAccessKey,
  },
});

/**
 * Checks if a given URL is a valid S3 URL and if the corresponding object exists in the bucket.
 * This function uses the S3 HeadObjectCommand to efficiently check for the object's existence
 * without downloading the content.
 *
 * @param url The S3 URL to validate.
 * @returns A promise that resolves to `true` if the URL is valid and the object exists, otherwise `false`.
 */
async function isValidS3URL(url: string): Promise<boolean> {
  // console.log(`Checking if ${url} is valid`);
  try {
    // 1. Parse the URL to get the bucket and key.
    const urlObject = new URL(url);
    // The bucket name is typically the first part of the hostname,
    // e.g., "pixika5-live" in "pixika5-live.s3.ap-south-1.amazonaws.com"
    const bucket = urlObject.hostname.split(".")[0];
    // The key is the pathname, e.g., "/assets/calendar/faceswap/superheros/male/square/4.png",
    // with the leading slash removed.
    const key = urlObject.pathname.substring(1);

    // 2. Use the S3 HeadObjectCommand to check if the object exists.
    // This command only retrieves metadata, making it a very lightweight check.
    const command = new HeadObjectCommand({
      Bucket: bucket,
      Key: key,
    });

    await s3.send(command);

    // If the command succeeds, the object exists.
    return true;
  } catch (error) {
    // 3. Handle potential errors.
    // If the object does not exist, the SDK will throw a NotFound error.
    if (error instanceof NotFound) {
      return false;
    }

    // Handle other errors, such as invalid URL format or permission issues.
    console.error(
      `An error occurred while validating the URL '${url}':`,
      error
    );
    return false;
  }
}

function getResultingURL(
  sourceImageURL: string,

  targetImageURL: string
): string {
  const suffix = targetImageURL

    ?.split("/faceswap/")

    .at(-1)

    ?.split(".")

    .slice(0, -1)

    ?.at(0)

    ?.split("/")

    ?.join("-");

  if (!suffix) throw new Error("Invalid target image URL");

  const newURL =
    sourceImageURL.split(".").slice(0, -1).join(".") + `-${suffix}.png`;

  return newURL;
}

async function pullDetails(message: any) {
  const response = await axios.get(
    `https://cam5.pixika.ai/api/v1/CSubmission/${message.Body}`,
    {
      headers: { "x-api-key": config.espo.key },
    }
  );
  return {
    calendarId: message.Body,
    details: response.data,
  };
}

async function main() {
  for (const calendarId of uniqueSubmittedCalendarIds) {
    console.log(`Checking ${calendarId}`);

    const details = await pullDetails({ Body: calendarId });
    const sourceURL = details.details.faceImageURL;

    // get target urls
    const count = calendarIdCountMap.get(calendarId) || 12;
    const targetURLs: string[] = [];
    for (let i = 1; i <= count; i++) {
      const url = details.details[`ef${i}`];
      if (url) {
        // this is needed to remove the null values
        targetURLs.push(url);
      }
    }
    // const targetURLs = [
    //   details.details.ef1,
    //   details.details.ef2,
    //   details.details.ef3,
    //   details.details.ef4,
    //   details.details.ef5,
    //   details.details.ef6,
    //   details.details.ef7,
    //   details.details.ef8,
    //   details.details.ef9,
    //   details.details.ef10,
    //   details.details.ef11,
    //   details.details.ef12,
    // ];

    let doAllURLsExist = true;
    for (const targetURL of targetURLs) {
      const doesExist = await isValidS3URL(targetURL);
      if (!doesExist) {
        doAllURLsExist = false;
        break;
      }
    }

    if (doAllURLsExist) {
      console.log(`${calendarId} is complete`);
    } else {
      console.log(`${calendarId} is incomplete`);
    }
  }
}

main();
