"use strict";
/*
 * @adonisjs/bodyparser
 *
 * (c) Harminder Virk <virk@adonisjs.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.File = void 0;
/// <reference path="../../adonis-typings/bodyparser.ts" />
const slash_1 = __importDefault(require("slash"));
const path_1 = require("path");
const utils_1 = require("@poppinss/utils");
const fs_extra_1 = require("fs-extra");
const helpers_1 = require("@poppinss/utils/build/helpers");
const Size_1 = require("./Validators/Size");
const Extensions_1 = require("./Validators/Extensions");
/**
 * The file holds the meta/data for an uploaded file, along with
 * an errors occurred during the upload process.
 */
class File {
    /**
     * Whether or not the validations have been executed
     */
    get validated() {
        return this.sizeValidator.validated && this.extensionValidator.validated;
    }
    /**
     * A boolean to know if file has one or more errors
     */
    get isValid() {
        return this.errors.length === 0;
    }
    /**
     * Opposite of [[this.isValid]]
     */
    get hasErrors() {
        return !this.isValid;
    }
    /**
     * The maximum file size limit
     */
    get sizeLimit() {
        return this.sizeValidator.maxLimit;
    }
    set sizeLimit(limit) {
        this.sizeValidator.maxLimit = limit;
    }
    /**
     * Extensions allowed
     */
    get allowedExtensions() {
        return this.extensionValidator.extensions;
    }
    set allowedExtensions(extensions) {
        this.extensionValidator.extensions = extensions;
    }
    constructor(data, validationOptions, drive) {
        this.data = data;
        this.drive = drive;
        this.sizeValidator = new Size_1.SizeValidator(this);
        this.extensionValidator = new Extensions_1.ExtensionValidator(this);
        /**
         * A boolean to know if file is an instance of this class
         * or not
         */
        this.isMultipartFile = true;
        /**
         * Field name is the name of the field
         */
        this.fieldName = this.data.fieldName;
        /**
         * Client name is the file name on the user client
         */
        this.clientName = this.data.clientName;
        /**
         * The headers sent as part of the multipart request
         */
        this.headers = this.data.headers;
        /**
         * File size in bytes
         */
        this.size = 0;
        /**
         * Upload errors
         */
        this.errors = [];
        /**
         * The file meta data
         */
        this.meta = {};
        /**
         * The state of the file
         */
        this.state = 'idle';
        this.sizeLimit = validationOptions.size;
        this.allowedExtensions = validationOptions.extnames;
    }
    /**
     * Validate the file
     */
    validate() {
        this.extensionValidator.validate();
        this.sizeValidator.validate();
    }
    /**
     * Mark file as moved
     */
    markAsMoved(fileName, filePath) {
        this.filePath = filePath;
        this.fileName = fileName;
        this.state = 'moved';
    }
    /**
     * Moves the file to a given location. Multiple calls to the `move` method are allowed,
     * incase you want to move a file to multiple locations.
     */
    async move(location, options) {
        if (!this.tmpPath) {
            throw new utils_1.Exception('tmpPath must be set on the file before moving it', 500, 'E_MISSING_FILE_TMP_PATH');
        }
        options = Object.assign({ name: this.clientName, overwrite: true }, options);
        const filePath = (0, path_1.join)(location, options.name);
        try {
            await (0, fs_extra_1.move)(this.tmpPath, filePath, { overwrite: options.overwrite });
            this.markAsMoved(options.name, filePath);
        }
        catch (error) {
            if (error.message.includes('dest already exists')) {
                throw new utils_1.Exception(`"${options.name}" already exists at "${location}". Set "overwrite = true" to overwrite it`, 500);
            }
            throw error;
        }
    }
    /**
     * Move file to a drive disk
     */
    async moveToDisk(location, options, diskName) {
        const driver = diskName ? this.drive.use(diskName) : this.drive.use();
        const fileName = driver.name === 'fake'
            ? this.clientName
            : options?.name
                ? options.name
                : `${(0, helpers_1.cuid)()}.${this.extname}`;
        /**
         * Move file as normal when using the local driver
         */
        if (driver.name === 'local') {
            await this.move(driver.makePath(location), {
                name: fileName,
                overwrite: true,
            });
            return;
        }
        /**
         * Make a unix style key for cloud drivers, since the cloud
         * key is not a filesystem path
         */
        const key = (0, slash_1.default)((0, path_1.join)(location || './', fileName));
        /**
         * Set the content type for cloud drivers
         */
        options = options || {};
        if (this.type && this.subtype && !options.contentType) {
            options.contentType = `${this.type}/${this.subtype}`;
        }
        if (options.contentLength === undefined) {
            options.contentLength = this.size;
        }
        await driver.putStream(key, (0, fs_extra_1.createReadStream)(this.tmpPath), options);
        this.markAsMoved(key, await driver.getUrl(key));
    }
    /**
     * Returns file JSON representation
     */
    toJSON() {
        return {
            fieldName: this.fieldName,
            clientName: this.clientName,
            size: this.size,
            filePath: this.filePath,
            fileName: this.fileName,
            type: this.type,
            extname: this.extname,
            subtype: this.subtype,
            state: this.state,
            isValid: this.isValid,
            validated: this.validated,
            errors: this.errors,
            meta: this.meta,
        };
    }
}
exports.File = File;
