// multer 설치
npm i multer
# File Access
ACCESS_FILE_POST_IMAGE_PATH=/files/posts
ACCESS_FILE_USER_PROFILE_PATH=/files/profiles

# File
FILE_POST_IMAGE_PATH=storage/images/posts
FILE_POST_IMAGE_SIZE=10485760
FILE_USER_PROFILE_PATH=storage/images/profiles
FILE_USER_PROFILE_SIZE=10485760
/**
 * @file app/middlewares/multer/uploaders/profile.uploader.js
 * @description 게시글 이미지 업로드
 * 251127 v1.0.0 CK init
 */

import multer from 'multer';
import fs from 'fs';
import dayjs from 'dayjs'
import myError from '../../../errors/customs/my.error.js'
import { BAD_FILE_ERROR } from '../../../../configs/responseCode.config.js';

/**
 * 게시글 이미지 업로드 처리 미들웨어
 * @param {import("express").Request} req 
 * @param {import("express").Response} res 
 * @param {import("express").NextFunction} next 
 */
export default function(req,res, next) {
  // multer 객체 정의
  const upload = multer({
    // storage: 파일을 저장할 위치를 상세하게 저장하는 프로퍼티
    storage: multer.diskStorage({
      // 파일 저장 경로 설정
      destination(req, file, callback) {
        // 저장 디렉토리 설정
        if(!fs.existsSync(process.env.FILE_USER_PROFILE_PATH)) {
          // 해당 디렉토리 없으면 생성 처리
          fs.mkdirSync(
            process.env.FILE_USER_PROFILE_PATH,
            {
              recursive: true, // 중간 디렉토리까지 모두 생성
              mode: 0o755      // 권한 설정 rwxr-xr-x
            }
          )
        }
        
        callback(null, process.env.FILE_USER_PROFILE_PATH);
      },
      // 파일명 설정
      filename(req, file, callback) {
        // 저장할 파일명 생성
        const uniqueFileName = `${dayjs().format('YYYYMMDD')}_${crypto.randomUUID()}`;
        const fileNameParts = file.originalname.split('.');
        const extention = fileNameParts[fileNameParts.length - 1].toLowerCase();

        callback(null, `${uniqueFileName}.${extention}`);
      }
    }),
    // fileFilter: 파일 필터링 처리를 제어하는 프로퍼티
    fileFilter(req, file, callback) {
      if(!file.mimetype.startsWith('image/')) {
        return callback(myError('이미지 파일 아님', BAD_FILE_ERROR));
      }
      callback(null, true);
    },
    // limits: 파일 사이즈 제한, 파일 개수 제한
    limits: {
      fileSize: parseInt(process.env.FILE_USER_PROFILE_SIZE)
    }
  }).single('image');

  // 예외 처리
  upload(req, res, err => {
    if(err instanceof multer.MulterError || err) {
      next(myError(err.message, BAD_FILE_ERROR));
    }
    next();
  });
}
/**
 * @file app/middlewares/multer/uploaders/profile.uploader.js
 * @description 게시글 이미지 업로드
 * 251127 v1.0.0 CK init
 */

import multer from 'multer';
import fs from 'fs';
import dayjs from 'dayjs'
import myError from '../../../errors/customs/my.error.js'
import { BAD_FILE_ERROR } from '../../../../configs/responseCode.config.js';

/**
 * 게시글 이미지 업로드 처리 미들웨어
 * @param {import("express").Request} req 
 * @param {import("express").Response} res 
 * @param {import("express").NextFunction} next 
 */
export default function(req,res, next) {
  // multer 객체 정의
  const upload = multer({
    // storage: 파일을 저장할 위치를 상세하게 저장하는 프로퍼티
    storage: multer.diskStorage({
      // 파일 저장 경로 설정
      destination(req, file, callback) {
        // 저장 디렉토리 설정
        if(!fs.existsSync(process.env.FILE_USER_PROFILE_PATH)) {
          // 해당 디렉토리 없으면 생성 처리
          fs.mkdirSync(
            process.env.FILE_USER_PROFILE_PATH,
            {
              recursive: true, // 중간 디렉토리까지 모두 생성
              mode: 0o755      // 권한 설정 rwxr-xr-x
            }
          )
        }
        
        callback(null, process.env.FILE_USER_PROFILE_PATH);
      },
      // 파일명 설정
      filename(req, file, callback) {
        // 저장할 파일명 생성
        const uniqueFileName = `${dayjs().format('YYYYMMDD')}_${crypto.randomUUID()}`;
        const fileNameParts = file.originalname.split('.');
        const extention = fileNameParts[fileNameParts.length - 1].toLowerCase();

        callback(null, `${uniqueFileName}.${extention}`);
      }
    }),
    // fileFilter: 파일 필터링 처리를 제어하는 프로퍼티
    fileFilter(req, file, callback) {
      if(!file.mimetype.startsWith('image/')) {
        return callback(myError('이미지 파일 아님', BAD_FILE_ERROR));
      }
      callback(null, true);
    },
    // limits: 파일 사이즈 제한, 파일 개수 제한
    limits: {
      fileSize: parseInt(process.env.FILE_USER_PROFILE_SIZE)
    }
  }).single('image');

  // 예외 처리
  upload(req, res, err => {
    if(err instanceof multer.MulterError || err) {
      next(myError(err.message, BAD_FILE_ERROR));
    }
    next();
  });
}
/**
 * @file app/middlewares/multer/multer.middleware.js
 * @description multer 미들웨어(업로더를 모아서 내보내기)
 * 251127 v1.0.0 CK init
 */

import postUploader from "./uploaders/post.uploader.js";
import profileUploader from "./uploaders/profile.uploader.js";

export default {
  postUploader,
  profileUploader,
}
/**
 * @file app/controllers/files.controller.js
 * @description 파일 업로드 관련 컨트롤러
 * 251127 v1.0.0 CK init
 */

import { BAD_FILE_ERROR, SUCCESS } from "../../configs/responseCode.config.js";
import myError from "../errors/customs/my.error.js";
import { createBaseResponse } from "../utils/createBaseResponse.util.js";

/**
 * 게시글 이미지 업로드 컨트롤러
 * @param {import("express").Request} req - Request 객체
 * @param {import("express").Response} res - Response 객체
 * @param {import("express").NextFunction} next - NextFunction 객체 
 * @returns
 */
async function storePost(req, res, next) {
  try {
    // 파일 여부 확인
    if(!req.file) {
      throw myError('파일 없음', BAD_FILE_ERROR);
    }

    const result = {
      path: `${process.env.APP_URL}${process.env.ACCESS_FILE_POST_IMAGE_PATH}/${req.file.filename}` 
    };

    return res.status(SUCCESS.status).send(createBaseResponse(SUCCESS, result));
  } catch (error) {
    next(error);
  }
}

/**
 * 유저 프로필 업로드 컨트롤러
 * @param {import("express").Request} req - Request 객체
 * @param {import("express").Response} res - Response 객체
 * @param {import("express").NextFunction} next - NextFunction 객체 
 * @returns
 */
async function storeProfile(req, res, next) {
  try {
    // 파일 여부 확인
    if(!req.file) {
      throw myError('파일 없음', BAD_FILE_ERROR);
    }

    const result = {
      path: `${process.env.APP_URL}${process.env.ACCESS_FILE_USER_PROFILE_PATH}/${req.file.filename}` 
    };

    return res.status(SUCCESS.status).send(createBaseResponse(SUCCESS, result));
  } catch (error) {
    next(error);
  }
}

export default {
  storePost,
  storeProfile,
}
/**
 * @file routes/files.router.js
 * @description 파일 관련 라우터
 * 251127 v1.0.0 CK init 
 */

import express from 'express';
import multerMiddleware from '../app/middlewares/multer/multer.middleware.js';
import filesController from '../app/controllers/files.controller.js';
import authMiddleware from '../app/middlewares/auth/auth.middleware.js';

const filesRouter = express.Router();

filesRouter.post('/posts', authMiddleware, multerMiddleware.postUploader, filesController.storePost); 
filesRouter.post('/profiles', authMiddleware, multerMiddleware.profileUploader, filesController.storeProfile); 

export default filesRouter;
// ---------------------------
// 정적 파일 제공 등록
// ---------------------------
app.use(process.env.ACCESS_FILE_POST_IMAGE_PATH, express.static(process.env.FILE_POST_IMAGE_PATH));
app.use(process.env.ACCESS_FILE_USER_PROFILE_PATH, express.static(process.env.FILE_USER_PROFILE_PATH));

// ---------------------------
// 라우터 정의
// ---------------------------
app.use('/api/files', filesRouter);