"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var CsvService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.CsvService = void 0;
const common_1 = require("@nestjs/common");
const fast_csv_1 = require("fast-csv");
const error_messages_1 = require("../constants/error-messages");
const stream_1 = require("stream");
;
const DEFAULT_PAGE_SIZE = 100;
let CsvService = CsvService_1 = class CsvService {
    constructor() {
        this.logger = new common_1.Logger(CsvService_1.name);
    }
    async createCsvStream(getDataRecords = null, chunkSize = 100, headers = []) {
        if (headers.length === 0 && typeof getDataRecords !== 'function') {
            throw new Error(error_messages_1.ERROR_MESSAGES.MISSING_HEADERS_OR_FUNCTION);
        }
        if (getDataRecords && chunkSize <= 0) {
            throw new Error(error_messages_1.ERROR_MESSAGES.INVALID_CHUNK_SIZE);
        }
        const passThrough = new stream_1.PassThrough();
        const csvStream = headers.length
            ? (0, fast_csv_1.format)({ headers })
            : (0, fast_csv_1.format)({ headers: true });
        csvStream.pipe(passThrough);
        try {
            if (typeof getDataRecords !== 'function') {
                const dummyRow = headers.reduce((acc, header) => {
                    acc[header] = '';
                    return acc;
                }, {});
                csvStream.write(dummyRow);
                csvStream.end();
                return passThrough;
            }
            let chunkIndex = 0;
            while (true) {
                const records = await getDataRecords(chunkIndex, chunkSize);
                if (records.length === 0)
                    break;
                for (const record of records) {
                    csvStream.write(record);
                }
                chunkIndex++;
                this.logger.debug(`✅ Chunk ${chunkIndex} written to CSV`);
            }
            csvStream.end();
        }
        catch (error) {
            this.logger.error(`❌ Error writing CSV: ${error.message}`);
            passThrough.destroy(error);
            throw error;
        }
        return passThrough;
    }
    async *readCsvInPagesFromStream(stream, options) {
        const { pageSize = DEFAULT_PAGE_SIZE, hasHeaderRow = true, providedHeaders = [] } = options || {};
        let headers = [];
        let page = [];
        let isFirstRow = true;
        let hasYieldedData = false;
        const parser = (0, fast_csv_1.parse)({ headers: hasHeaderRow, renameHeaders: false, trim: true });
        const parsingStream = stream.pipe(parser);
        for await (const row of parsingStream) {
            if (isFirstRow && !hasHeaderRow) {
                isFirstRow = false;
                if (providedHeaders.length) {
                    headers = providedHeaders;
                }
                else {
                    headers = Object.keys(row).length > 0 ? Object.keys(row).map((_, i) => i.toString()) : [];
                }
            }
            if (hasHeaderRow && isFirstRow) {
                headers = Object.keys(row);
                isFirstRow = false;
            }
            if (!headers.length) {
                headers = providedHeaders.length ? providedHeaders : Object.keys(row);
            }
            const record = {};
            for (let i = 0; i < headers.length; i++) {
                const key = headers[i];
                const value = row[key] ?? Object.values(row)[i] ?? null;
                record[key] = value;
            }
            if (Object.values(record).every(v => v === null || v === ''))
                continue;
            page.push(record);
            if (page.length === pageSize) {
                yield { headers, data: page };
                hasYieldedData = true;
                page = [];
            }
        }
        if (page.length > 0) {
            yield { headers, data: page };
            hasYieldedData = true;
        }
        if (!hasYieldedData && headers.length > 0) {
            yield { headers, data: [] };
        }
    }
};
exports.CsvService = CsvService;
exports.CsvService = CsvService = CsvService_1 = __decorate([
    (0, common_1.Injectable)()
], CsvService);
//# sourceMappingURL=csv.service.js.map