import { URL } from 'url';
import { DataLakeServiceClient, DataLakeDirectoryClient } from '@azure/storage-file-datalake';
import * as path from 'path';

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;
        console.log(`Initialized SarvamClient with directory: ${this.directoryName}`);
    }

    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;
        console.log(`Updated URL to directory: ${this.directoryName}`);
    }

    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(localFilePaths: string[]): Promise<void> {
        console.log(`Starting upload of ${localFilePaths.length} files`);
        const directoryClient = new DataLakeDirectoryClient(`${this.accountUrl}/${this.fileSystemName}/${this.directoryName}/?${this.sasToken}`);
        
        const tasks = localFilePaths.map(async filePath => {
            const fileName = path.basename(filePath);
            return this.uploadFile(directoryClient, fileName);
        });

        await Promise.all(tasks);
        console.log('Upload completed');
    }

    private async uploadFile(directoryClient: DataLakeDirectoryClient, fileName: string): Promise<boolean> {
        try {
            const fileClient = directoryClient.getFileClient(fileName);
            await fileClient.uploadFile(fileName);
            console.log(`File uploaded successfully: ${fileName}`);
            return true;
        } catch (error) {
            console.error(`Upload failed for ${fileName}: ${error}`);
            return false;
        }
    }

    async listFiles(): Promise<string[]> {
        console.log('\n Listing files in directory...');
        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!));
        }
        
        console.log(`Found ${fileNames.length} files:`);
        fileNames.forEach(file => console.log(`${file}`));
        return fileNames;
    }

    async downloadFiles(fileNames: string[], destinationDir: string): Promise<void> {
        console.log(`\n Starting download of ${fileNames.length} files to ${destinationDir}`);        
        const directoryClient = new DataLakeDirectoryClient(`${this.accountUrl}/${this.fileSystemName}/${this.directoryName}/?${this.sasToken}`);
        
        const tasks = fileNames.map(fileName => this.downloadFile(directoryClient, fileName, destinationDir));
        await Promise.all(tasks);
        console.log('Download completed');
    }

    private async downloadFile(directoryClient: DataLakeDirectoryClient, fileName: string, destinationDir: string): Promise<boolean> {
        try {
            const fileClient = directoryClient.getFileClient(fileName);
            
            const response = await fileClient.read();
            const downloaded = await this.blobToString(await response.contentAsBlob);
            
            console.log(`Downloaded: ${fileName} -> ${downloaded}`);
            return true;
        } catch (error) {
            console.error(`Download failed for ${fileName}: ${error}`);
            return false;
        }
    }

    private async blobToString(blob: Blob): Promise<string> {
        const fileReader = new FileReader();
        return new Promise<string>((resolve, reject) => {
          fileReader.onloadend = (ev: any) => {
            resolve(ev.target!.result);
          };
          fileReader.onerror = reject;
          fileReader.readAsText(blob);
        });
    }
}

export default SarvamClient;
