import { Injectable, Logger } from "@nestjs/common";
import { Request } from "express";
import MediaLoadDto from "../../dto/media.dto";
import ResponseDto from "../../dto/response.dto";
import * as fs from 'fs';
import { v4 } from "uuid";
import { EntityManager } from "typeorm";
import MediaEntity from "../../entity/media.entity";
import process from "process";


@Injectable()
export default class MediaProvider {

    private logger: Logger = new Logger(MediaProvider.name);

    constructor(private readonly entityManager: EntityManager){}

    /**
     * Load new media
     * @param payload 
     */
    async loadMedia(payload: MediaLoadDto): Promise<ResponseDto>{

        const response: ResponseDto = new ResponseDto();

        try{

            if(payload.base64File?.includes(",")){
                payload.base64File = payload.base64File.split(",")[1];
            }

            const bytes     = Buffer.from(payload.base64File!, 'base64');            
            const filename  = v4();

            await this.entityManager.transaction(async (txn) => {

                const media: MediaEntity    = new MediaEntity();
                media.title                 = payload.title;
                media.uuid                  = filename;
                media.extension             = payload.extension;

                await txn.save(media);

                const basePath  = process.cwd();
                const dirPath   = `${basePath}/public/media/`;

                if(!fs.existsSync(dirPath)){
                    fs.mkdirSync(dirPath, {recursive: true});
                }

                // I something fail, transactions rollbacks!
                fs.writeFileSync(`${dirPath}${filename}.${payload.extension}`, bytes);
            });

            response.success = true;
            response.data    = { "path": `/media/${filename}.png` };

        }catch(e: any){
            this.logger.error(e.message);
        }

        return response;
    }

    /**
     * List media
     * @param request 
     * @param idNext 
     */
    async listMedia(idNext?: string, filter?: string): Promise<ResponseDto>{

        const response: ResponseDto = new ResponseDto();

        try{

            let where                   = "";
            const whereParts: string[]  = [];
            const values: any[]         = [];

            if(idNext){
                if(Number.isNaN(idNext)){
                   throw new Error("invalid_id_next"); 
                }
                whereParts.push("id < ?");
                values.push(idNext);
            }
            if(filter){
                whereParts.push('title LIKE ?');
                values.push(`%${filter}%`);
            }
            if(whereParts.length > 0){
                where = `WHERE ${whereParts.join(" AND ")}`;
            }

            const result = 
                await this.entityManager.query(
                    `SELECT id, uuid, title, CONCAT('/media/', uuid, '.', extension) fullPath FROM media ${where} ORDER BY id DESC LIMIT 100`,
                    values
                );

            response.success = true;
            response.data    = result;

        }catch(e: any){
            this.logger.error(e.message);
        }

        return response;    
    }

    /**
     * Trash media
     * @param request 
     * @param uuid 
     */
    async trashMedia(uuid: string): Promise<ResponseDto>{

        const response: ResponseDto = new ResponseDto();

        try{

            await this.entityManager.transaction(async (txn) => {

                const resultFiles = await txn.query(`SELECT CONCAT(uuid, '.', extension) filename FROM media WHERE uuid = ? LIMIT 1`, [uuid]);
                let filename = null;
                if(resultFiles.length > 0){
                    filename = resultFiles[0]['filename'];
                }
                await txn.query(`DELETE FROM media WHERE uuid = ?`, [uuid]);
                if(filename){
                    const basePath = `${process.cwd()}/public/media/${filename}`;
                    if(fs.existsSync(basePath)){
                        fs.unlinkSync(basePath);
                    }
                }

            });

            response.success = true;

        }catch(e: any){
            this.logger.error(e.message);
        }

        return response;
    }

}