const fs = require('fs');
const path = require('path');
const { File, Page } = require('../models');
const { v4: uuidv4 } = require('uuid');

const uploadDir = path.join(__dirname, '..', 'files', 'uploads');

const uploadFile = (req, res, next) => {
  if (!req.file) {
    return res.status(400).send('No file uploaded.');
  }
  if (!fs.existsSync(uploadDir)) {
    fs.mkdirSync(uploadDir, { recursive: true });
  }
  const file = req.file;
  const hash = uuidv4();
  const filePath = path.join(uploadDir, hash + path.extname(file.originalname));
  try {
    fs.writeFileSync(filePath, file.buffer);
    req.fileData = {
      hash: hash,
      title: req.body.title || file.originalname,
      originalName: file.originalname,
      path: filePath
    };
    next();
  } catch (error) {
    return res.status(500).send('File upload failed.');
  }
};

const saveFileDetails = async (req, res) => {
  try {
    const { hash, title, originalName, path } = req.fileData;
    const newFile = await File.create({
      hash,
      title,
      originalName,
      path
    });
    res.status(201).json(newFile);
  } catch (error) {
    console.log(error);
    res.status(500).json({ error: 'Failed to save file details.' });
  }
};

const getFiles = async (req, res) => {
  try {
    const files = await File.findAll();
    res.status(200).json(files);
  } catch (error) {
    res.status(500).json({ error: 'Failed to fetch files.' });
  }
};

const getFilesByPage = async (req, res) => {
  try {
    const { pageId } = req.params;
    const page = await Page.findByPk(pageId, {
      include: [File]
    });
    if (!page) {
      return res.status(404).json({ error: 'Page not found.' });
    }
    res.status(200).json(page.Files);
  } catch (error) {
    res.status(500).json({ error: 'Failed to fetch files for the page.' });
  }
};

const getFileById = async (req, res) => {
  try {
    const { id } = req.params;
    const file = await File.findByPk(id);
    if (!file) {
      return res.status(404).json({ error: 'File not found.' });
    }
    res.status(200).json(file);
  } catch (error) {
    res.status(500).json({ error: 'Failed to fetch file.' });
  }
};

const getFileByHash = async (req, res) => {
  try {
    const { hash } = req.params;
    const file = await File.findOne({ where: { hash } });
    if (!file) {
      return res.status(404).json({ error: 'File not found.' });
    }
    res.status(200).json(file);
  } catch (error) {
    res.status(500).json({ error: 'Failed to fetch file.' });
  }
};

const downloadFile = async (req, res) => {
  try {
    const { hash } = req.params;
    const file = await File.findOne({ where: { hash } });
    if (!file) {
      return res.status(404).json({ error: 'File not found.' });
    }
    const filePath = path.join(__dirname, '..', 'files', 'uploads', hash + path.extname(file.originalName));
    res.download(filePath, file.originalName, (err) => {
      if (err) {
        res.status(500).send({
          message: "Could not download the file. " + err,
        });
      }
    });
  } catch (error) {
    console.log(error);
    res.status(500).json({ error: 'Failed to download file.' });
  }
};

const updateFile = async (req, res) => {
  try {
    const { id } = req.params;
    const { title } = req.body;
    const file = await File.findByPk(id);
    if (!file) {
      return res.status(404).json({ error: 'File not found.' });
    }
    file.title = title || file.title;
    await file.save();
    res.status(200).json(file);
  } catch (error) {
    res.status500.json({ error: 'Failed to update file.' });
  }
};

module.exports = {
  uploadFile,
  saveFileDetails,
  getFiles,
  getFilesByPage,
  getFileById,
  getFileByHash,
  downloadFile,
  updateFile,
};
