import { URL } from "url";
import {
  DataLakeServiceClient,
  DataLakeDirectoryClient,
} from "@azure/storage-file-datalake";
import * as path from "path";
import { Response } from "express";
import * as archiver from "archiver";
import * as unzipper from 'unzipper';
import { PassThrough,Readable } from 'stream';

class SarvamClient {
  private accountUrl: string;
  private fileSystemName: string;
  private directoryName: string;
  private sasToken: string;

  constructor(url: string) {
    const components = this.extractUrlComponents(url);
    this.accountUrl = components.accountUrl;
    this.fileSystemName = components.fileSystemName;
    this.directoryName = components.directoryName;
    this.sasToken = components.sasToken;
  }

  updateUrl(url: string): void {
    const components = this.extractUrlComponents(url);
    this.accountUrl = components.accountUrl;
    this.fileSystemName = components.fileSystemName;
    this.directoryName = components.directoryName;
    this.sasToken = components.sasToken;
  }

  private extractUrlComponents(url: string) {
    const parsedUrl = new URL(url);
    const accountUrl = parsedUrl.origin.replace(".blob.", ".dfs.");
    const pathComponents = parsedUrl.pathname.replace(/^\//, "").split("/");
    const fileSystemName = pathComponents[0];
    const directoryName = pathComponents.slice(1).join("/");
    const sasToken = parsedUrl.search.substring(1);

    return { accountUrl, fileSystemName, directoryName, sasToken };
  }

  async uploadFiles(files: Express.Multer.File[]): Promise<void> {
    const directoryClient = new DataLakeDirectoryClient(
      `${this.accountUrl}/${this.fileSystemName}/${this.directoryName}/?${this.sasToken}`
    );

    const tasks = files.map(async (file) => {
      const fileName = file.originalname;
      return this.uploadFile(
        directoryClient,
        fileName,
        file.buffer,
        file.mimetype
      );
    });

    await Promise.all(tasks);
  }

  private async uploadFile(
    directoryClient: DataLakeDirectoryClient,
    fileName: string,
    fileContent: Buffer,
    mimeType: string
  ): Promise<boolean> {
    try {
      const fileClient = directoryClient.getFileClient(fileName);

      await fileClient.create();
      await fileClient.append(fileContent, 0, fileContent.length);
      await fileClient.flush(fileContent.length);
      await fileClient.setHttpHeaders({ contentType: mimeType });

      return true;
    } catch (error) {
      console.error(`Upload failed for ${fileName}: ${error}`);
      return false;
    }
  }

  async listFiles(): Promise<string[]> {
    const fileNames: string[] = [];
    const datalakeServiceClient = new DataLakeServiceClient(
      `${this.accountUrl}?${this.sasToken}`
    );
    const fileSystemClient = datalakeServiceClient.getFileSystemClient(
      this.fileSystemName
    );

    for await (const pathItem of fileSystemClient.listPaths({
      path: this.directoryName,
    })) {
      fileNames.push(path.basename(pathItem.name!));
    }

    fileNames.forEach((file) => console.log(`${file}`));
    return fileNames;
  }

  async imageToBase64(imageBuffer: Buffer): Promise<string> {
    return imageBuffer.toString('base64');
  }
  async downloadFileToResponse(res: Response): Promise<void> {
    try {
      const directoryClient = new DataLakeDirectoryClient(
        `${this.accountUrl}/${this.fileSystemName}/${this.directoryName}/?${this.sasToken}`
      );
      const files = await this.listFiles();

      res.setHeader("Content-Type", "application/zip");
      res.setHeader("Content-Disposition", "attachment; filename=files.zip");

      const archive = archiver("zip", { zlib: { level: 9 } });
      archive.pipe(res);

      for (const fileName of files) {
        const fileClient = directoryClient.getFileClient(fileName);
        const readResponse = await fileClient.read();

        if (readResponse.readableStreamBody) {
          const nodeReadableStream = Readable.from(
            readResponse.readableStreamBody
          );
          archive.append(nodeReadableStream, { name: fileName });
        } else {
          console.error(`Failed to read file: ${fileName}`);
        }
      }

      await archive.finalize();
    } catch (error) {
      console.error(`Error downloading files from storage path}:`, error);
      res.status(500).send(`Failed to download from storage path`);
    }
  }

  async readZipContents(): Promise<any> {
    const directoryClient = new DataLakeDirectoryClient(
      `${this.accountUrl}/${this.fileSystemName}/${this.directoryName}/?${this.sasToken}`
    );
  
    const files = await this.listFiles();
  
    const archive = archiver('zip', { zlib: { level: 9 } });
    const zipStream = new PassThrough();
  
    archive.pipe(zipStream);
  
    for (const fileName of files) {
      const fileClient = directoryClient.getFileClient(fileName);
      const readResponse = await fileClient.read();
  
      if (readResponse.readableStreamBody) {
        const nodeReadableStream = Readable.from(readResponse.readableStreamBody);
        archive.append(nodeReadableStream, { name: fileName });
      }
    }
  
    await archive.finalize();
  
    const chunks: Buffer[] = [];
    for await (const chunk of zipStream) {
      chunks.push(chunk);
    }
    const zipBuffer = Buffer.concat(chunks);
  
    const directory = await unzipper.Open.buffer(zipBuffer);
    let output = "";
    for (const file of directory.files) {
      const content = await file.buffer(); 
      
      output +=` `+JSON.parse(content.toString()).transcript
    }
    return output;
  }

}

export default SarvamClient;
