import axios from 'axios';
import B2 from 'backblaze-b2';
import {v4 as uuidv4} from 'uuid';
import {getLogger} from "@/utils/logger";

const logger = getLogger("backblaze");

const MAX_RETRIES = 5

interface UploadFileResponse {
  success: boolean;
  fileUrl?: string;
  fileId?: string;
  UniqueFileName?: string;
}

export async function UploadFIle(fileName: any, fileType: any, fileContent: any, bucketId: string):Promise<UploadFileResponse> {
  try {
    const b2 = new B2({
      applicationKey: process.env.BACKBLAZE_APP_KEY ?? "",
      applicationKeyId: process.env.BACKBLAZE_APP_KEY_ID ?? "",
    });

    try {
      await b2.authorize();
      // console.log("Authorization successful !")
    } catch (error: any) {
      logger.error("Backblaze authorization failed", { applicationKey: process.env.BACKBLAZE_APP_KEY, applicationKeyId: process.env.BACKBLAZE_APP_KEY_ID, error: error.config.data });
      return { success: false }
    }

    let delay_ms = 1000;
    for (let i = 0; i < MAX_RETRIES; i++) {
      try {
        const uploadUrlResponse = await b2.getUploadUrl({
          bucketId: bucketId,
        });

        const { uploadUrl, authorizationToken } = uploadUrlResponse.data;

        const UniqueFileName = UniqueFileNameGenerator(fileName)

        const uploadRes = await b2.uploadFile({
          uploadUrl,
          uploadAuthToken: authorizationToken,
          fileName: encodeURIComponent(UniqueFileName),
          mime: fileType,
          data: Buffer.from(fileContent, 'base64'),
          hash: 'do_not_verify',
        });

        const fileId = uploadRes.data.fileId
        // const link = uploadRes.file_url

        const fileUrl = `https://f005.backblazeb2.com/file/${process.env.BACKBLAZE_PUBLIC_BUCKET_NAME}/${UniqueFileName}`;

        logger.info("Upload Successful", {fileUrl:fileUrl, fileId: fileId, UniqueFileName: UniqueFileName});

        // return { success: true, fileUrl: fileUrl, fileId: fileId, UniqueFileName: UniqueFileName }
        return {
          success: true,
          fileUrl: fileUrl,
          fileId: fileId,
          UniqueFileName: UniqueFileName,
        };
      } catch (error: any) {
        logger.error("Error uploading content:", { error: error.config.data, responseStatus: error.response.status });

        // console.error(`Error uploading content: ${error.message}`);
   /*     if (error.response) {
          console.error(`Response status: ${error.response.status}`);
        }*/

        // Don't say we're retrying if it's the last time round the loop
        if (i < (MAX_RETRIES - 1)) {
          logger.warn(`Waiting ${delay_ms} milliseconds before retry.`, null);
          // Exponential backoff to allow transient issues to resolve
          await new Promise(resolve => setTimeout(resolve, delay_ms));
          delay_ms *= 2;
        }
      }
    }

    logger.warn(`Retried ${MAX_RETRIES} times. Returning an error response.`, null);
    return { success: false }
  } catch (error: any) {
    logger.error("File upload failed", { error: error.config.data });
    throw error;
  }
}


async function getAuthorizationToken() {
  try {
    const response = await axios.get('https://api.backblazeb2.com/b2api/v2/b2_authorize_account', {
      auth: {
        username: process.env.BACKBLAZE_APP_KEY_ID ?? '',
        password: process.env.BACKBLAZE_APP_KEY ?? '',
      },
    });


    return response.data;
  } catch (error: any) {
    logger.error("Backblaze authorization token generation failed", { error: error.config.data });
    throw error;
  }
}

async function getDownloadAuthorizationByFileName(bucketId: any, fileNamePrefix: any, validDurationInSeconds: any): Promise<[string, string]> {

  try {
    const { apiUrl, authorizationToken } = await getAuthorizationToken();

    const response = await axios.post(
        `${apiUrl}/b2api/v2/b2_get_download_authorization`,
        {
          bucketId,
          fileNamePrefix,
          validDurationInSeconds,
        },
        {
          headers: { Authorization: authorizationToken },
        }
    )

    return [response.data.authorizationToken, apiUrl]
  } catch (error:any) {
    logger.error("Backblaze download(by filename) authorization token generation failed", { fileNamePrefix:fileNamePrefix, error: error.config.data });
    throw error;
  }

}

async function getDownloadAuthorizationByFileId(bucketId: any, fileId: any, validDurationInSeconds: any) {
  try {
    const { data: authData } = await getAuthorizationToken();

    // const response = await axios.post(
    //   `${apiUrl}/b2api/v2/b2_get_download_authorization`,
    //   {
    //     bucketId,
    //     fileId,
    //     validDurationInSeconds,
    //   },
    //   {
    //     headers: { Authorization: authorizationToken },
    //   }
    // );

    // return response.data.authorizationToken;

    const downloadUrl = `${authData.downloadUrl}/b2api/v2/b2_download_file_by_id?fileId=${fileId}`;

    return downloadUrl;
  } catch (error:any) {
    logger.error("Backblaze download(by fileId) authorization token generation failed", { fileId:fileId, error: error.config.data });
    throw error;
  }
}

function constructDownloadUrl(apiUrl: any, bucketName: any, fileName: any, downloadAuthToken: any) {
  return `${apiUrl}/file/${process.env.BACKBLAZE_BUCKET_NAME}/${fileName}?Authorization=${downloadAuthToken}`;
}


export async function getPrivateFileByName(fileName: string) {
  try {

    // const { apiUrl, authorizationToken } = await getAuthorizationToken();

    const [downloadAuthToken, apiUrl]: [string, string] = await getDownloadAuthorizationByFileName(
      process.env.BACKBLAZE_BUCKET_ID,
      fileName,
      90000
    );

    const downloadUrl = constructDownloadUrl(apiUrl, process.env.B2_BUCKET_NAME, fileName, downloadAuthToken);

    return downloadUrl
  } catch ( error:any ) {
    logger.error("Backblaze private file download(by filename) authorization token generation failed", { fileName: fileName, error: error.config.data });
    throw error;
  }
}


// Test and verify this 
export async function getPrivateFileById(fileId: any, fileName: string) {
  try {
    const authResponse = await axios.get('https://api.backblazeb2.com/b2api/v2/b2_authorize_account', {
      auth: {
        username: process.env.BACKBLAZE_APP_KEY_ID ?? '',
        password: process.env.BACKBLAZE_APP_KEY ?? '',
      },
    });

    const {apiUrl, downloadUrl, authorizationToken} = authResponse.data;
    // Step 2: Construct the download URL
    const signedUrl = `${apiUrl}/b2api/v3/b2_download_file_by_id?fileId=${fileId}}`;

    return signedUrl;
  } catch (error:any) {
    logger.error("Backblaze private file download(by fileId) fileUrl generation failed", { error: error.config.data });
    throw error;
  }
}

// TEST THIS FUNCTION
export async function DeleteFileById(fileId: string, fileName: string, bucketId: string) {
  try {
    const b2 = new B2({
      applicationKey: process.env.BACKBLAZE_APP_KEY ?? "",
      applicationKeyId: process.env.BACKBLAZE_APP_KEY_ID ?? "",
    });

    await b2.authorize();
    const deleteFileResponse = await b2.deleteFileVersion({
      fileId: fileId,
      fileName: fileName,
    });

    return deleteFileResponse;
  } catch (error:any) {
    logger.error("Backblaze file delete operation failed", { error: error.config.data });
    // throw error;
  }
}

export const UniqueFileNameGenerator = (fileName:string) => {

  const IsExtension = fileName.split('.').length > 1
  const uuid = uuidv4()
  const timeStamp = new Date().toDateString().split(' ').join("0")
  if (IsExtension) {
    const [unused, extension] = fileName.split('.')
    
    return `${uuid}_${timeStamp}.${extension}`
  }

  return `${uuid}_${timeStamp}`

}