import { Storage } from "@google-cloud/storage";
import path from 'path';
import logger from "@utils/logger";

/** Optional layout for CPC/CSD objects (mirrors local `uploads/cpc-csd-files/...`). */
export type CpcGcsUploadOptions = {
    bucket?: string;
    /** Directory prefix inside the bucket, no leading slash, e.g. `cpc-csd/csd/BOOK-1/documents` */
    objectDir?: string;
    /** Final filename segment only (no path separators) */
    objectBaseName?: string;
};

class CpcGcsService {
    private storage: Storage;
    private bucketName: string;

    constructor() {
        this.storage = new Storage({
            projectId: process.env.GCP_PROJECT_ID,
            keyFilename: process.env.GCP_KEY_FILE
        });
        this.bucketName = process.env.GCP_BUCKET_NAME || '';
    }

    parseGsUrl(gsUrl: string) {
        if (!gsUrl || !gsUrl.startsWith("gs://")) throw new Error("INVALID_DOCUMENT_URL");
        const s = gsUrl.slice(5);
        const [bucket, ...rest] = s.split("/");
        const objectPath = rest.join("/");
        if (!bucket || !objectPath) throw new Error("INVALID_DOCUMENT_URL");
        return { bucket, objectPath };
    }

    async downloadFromGcs(gsUrl: string): Promise<Buffer> {
        const { bucket, objectPath } = this.parseGsUrl(gsUrl);
        const [buf] = await this.storage.bucket(bucket).file(objectPath).download();
        return buf;
    }

    /**
     * Third argument can be a legacy custom bucket string, or structured options for path layout.
     */
    async uploadToGcs(
        fileBuffer: Buffer,
        originalName: string,
        legacyBucketOrOpts?: string | CpcGcsUploadOptions
    ): Promise<string> {
        const opts: CpcGcsUploadOptions =
            typeof legacyBucketOrOpts === 'string' ? { bucket: legacyBucketOrOpts } : legacyBucketOrOpts || {};
        const targetBucket = opts.bucket || this.bucketName;
        const base =
            opts.objectBaseName && !opts.objectBaseName.includes('/') && !opts.objectBaseName.includes('..')
                ? opts.objectBaseName
                : `${Date.now()}-${path.basename(originalName)}`;
        const dir =
            opts.objectDir && !opts.objectDir.includes('..')
                ? opts.objectDir.replace(/^\/+|\/+$/g, '')
                : 'cpc-csd/uploads';
        const fileName = `${dir}/${base}`.replace(/\\/g, '/');
        const bucket = this.storage.bucket(targetBucket);
        const file = bucket.file(fileName);

        await file.save(fileBuffer);
        
        logger.info(`[CpcGcsService] File uploaded to gs://${targetBucket}/${fileName}`);
        return `gs://${targetBucket}/${fileName}`;
    }
}

export const cpcGcsService = new CpcGcsService();
