// page.js
// Copyright (C) 2022 DTP Technologies, LLC
// License: Apache-2.0

'use strict';

const fs = require('fs');

const express = require('express');
const mongoose = require('mongoose');

const { SiteController/*, SiteError*/ } = require('../../lib/site-lib');

class ImageController extends SiteController {

  constructor (dtp) {
    super(dtp, module.exports);

  }

  async start ( ) {
    const { dtp } = this;
    const { limiter: limiterService } = dtp.services;

    const router = express.Router();
    dtp.app.use('/image', router);

    const imageUpload = this.createMulter('uploads', {
      limits: {
        fileSize: 1024 * 1000 * 12,
      },
    });

    router.use(async (req, res, next) => {
      res.locals.currentView = 'image';
      return next();
    });

    router.param('imageId', this.populateImage.bind(this));

    router.post('/tinymce',
      imageUpload.single('file'),
      this.postTinyMceImage.bind(this),
    );

    router.post('/',
      limiterService.createMiddleware(limiterService.config.image.postCreateImage),
      imageUpload.single('file'),
      this.postCreateImage.bind(this),
    );

    router.get('/:imageId',
      limiterService.createMiddleware(limiterService.config.image.getImage),
      this.getHostCacheImage.bind(this),
      // this.getImage.bind(this),
    );
  }

  async populateImage (req, res, next, imageId) {
    try {
      res.locals.imageId = mongoose.Types.ObjectId(imageId);
      res.locals.image = await this.dtp.services.image.getImageById(res.locals.imageId);
      return next();
    } catch (error) {
      this.log.error('failed to populate image', { error });
      return next(error);
    }
  }

  async postTinyMceImage (req, res, next) {
    const { image: imageService } = this.dtp.services;
    try {
      res.locals.image = await imageService.create(req.user, req.body, req.file);
      res.status(200).json({ location: `/image/${res.locals.image._id}` });
    } catch (error) {
      this.log.error('failed to create image', { error });
      return next(error);
    }
  }

  async postCreateImage (req, res, next) {
    const { image: imageService } = this.dtp.services;
    try {
      res.locals.image = await imageService.create(req.user, req.body, req.file);
      res.status(200).json({
        success: true,
        imageId: res.locals.image._id.toString(),
      });
    } catch (error) {
      this.log.error('failed to create image', { error });
      return next(error);
    }
  }

  async getHostCacheImage (req, res) {
    const { hostCache: hostCacheService } = this.dtp.services;
    const { image } = res.locals;
    try {
      const fileInfo = await hostCacheService.getFile(image.file.bucket, image.file.key);
      const stream = fs.createReadStream(fileInfo.file.path);
      res.header('Content-Type', image.type);
      res.header('Content-Length', fileInfo.file.stats.size);
      res.status(200);
      stream.pipe(res);
    } catch (error) {
      this.log.error('failed to fetch image', { image, error });
      return res.status(error.statusCode || 500).json({
        success: false,
        message: error.message,
      });
    }
  }

  async getImage (req, res) {
    const { minio: minioService } = this.dtp.services;
    try {
      const stream = await minioService.openDownloadStream({
        bucket: res.locals.image.file.bucket,
        key: res.locals.image.file.key
      });
      res.header('Content-Type', res.locals.image.type);
      res.header('Content-Length', res.locals.image.size);
      res.status(200);
      stream.pipe(res);
    } catch (error) {
      return res.status(error.statusCode || 500).json({
        success: false,
        message: error.message,
      });
    }
  }
}

module.exports = {
  slug: 'image',
  name: 'image',
  create: async (dtp) => { return new ImageController(dtp); },
};
