import { NextFunction, Request, Response } from "express";
import formidable, { Fields, Files } from "formidable";
import { TypedRequestAuth } from "./auth.controller";
import { asyncWrap } from "../helpers";
import { postDb, userDb } from "../db";
import { TypedRequest } from "../types";
import { Types } from "mongoose";

export const userByPostId = async (
  reqExp: Request,
  res: Response,
  next: NextFunction,
  postId: string
) => {
  const req = reqExp as TypedRequest;

  req.user = await userDb.findUserByPostId(postId);
  next();
};

export const SubTract = (oldSet: Set<string>, newSet: Set<string>) => {
  const keep = new Array<string>(); //유지
  const drop = new Array<string>(); //삭제
  const add = new Array<string>(); //추가

  oldSet.forEach((oldname) => {
    drop.push(oldname);
    newSet.forEach((newname) => {
      add.push(newname);
      if (oldname === newname) {
        keep.push(oldname);
      }
    });
  });

  const addSet = new Set(add);
  const newAdd = [...addSet];

  // console.log("before delete drop ", drop);
  // console.log("before delete add ", add);

  for (var i = 0; i < drop.length; i++) {
    for (var j = 0; j < keep.length; j++) {
      if (drop[i] === keep[j]) {
        drop.splice(i, 1);
      }
    }
  }

  for (var i = 0; i < newAdd.length; i++) {
    for (var j = 0; j < keep.length; j++) {
      if (newAdd[i] === keep[j]) {
        newAdd.splice(i, 1);
      }
    }
  }

  // console.log("spliced add", add);

  const dropSet = new Set(drop);
  const newDrop = [...dropSet];

  const reAddSet = new Set(newAdd);
  const reNewAdd = [...reAddSet];

  const res = {
    keep: keep,
    drop: newDrop,
    add: reNewAdd,
  };

  return res;
};

//Create
export const createFileAndPost = asyncWrap(async (reqExp, res, next) => {
  const req = reqExp as TypedRequestAuth<{ userId: string }>;

  const { userId } = req.auth;

  const form = formidable({
    uploadDir: "uploads",
    keepExtensions: true,
    multiples: true,
  });

  const fileIdArr = new Array();

  form.parse(req, async (err, fields, files) => {
    if (!Array.isArray(fields.title)) {
      const title = fields.title;
      if (!Array.isArray(fields.text)) {
        const text = fields.text;
        if (!Array.isArray(fields.theme)) {
          const theme = fields.theme;
          if (!Array.isArray(fields.city)) {
            const city = fields.city;

            if (Array.isArray(files.picture)) {
              for (var i = 0; i < files.picture.length; i++) {
                const originalfilename = files.picture?.[i].originalFilename;
                const newfilename = files.picture?.[i].newFilename;
                const filepath = files.picture?.[i].filepath;

                const filesRes = await postDb.createFilesRow(
                  originalfilename,
                  newfilename,
                  filepath
                );

                fileIdArr.push(filesRes);
              }
            } else if (!Array.isArray(files.picture)) {
              const originalfilename = files.picture.originalFilename;
              const newfilename = files.picture.newFilename;
              const filepath = files.picture.filepath;

              const filesRes = await postDb.createFilesRow(
                originalfilename,
                newfilename,
                filepath
              );

              fileIdArr.push(filesRes);
            } // file or one or more

            const postRes = await postDb.createPostRow({
              title,
              text,
              theme,
              city,
              date: Date.now(),
              counts: 0,
              user: userId,
              file: fileIdArr,
            });

            return res.json(postRes);
          }
        }
      }
    }
  });
});

//Read
export const getAllPost = asyncWrap(async (req, res) => {
  const posts = await postDb.getPosts();

  return res.json(posts);
});

export const getFiles = asyncWrap(async (req, res) => {
  const { postId } = req.params;
  const files = await postDb.getFilesByPostId(postId);

  return res.json(files);
});

//Update
export const addCounts = asyncWrap(async (req, res) => {
  const { postId } = req.params;
  const { counts } = req.body as {
    counts: number;
  };
  const updateCounts = await postDb.addOneCount(postId, counts);

  return res.json(updateCounts);
});

export const updateOnePost = asyncWrap(async (reqExp, res) => {
  const req = reqExp as TypedRequestAuth<{ userId: string }>;
  const { userId } = req.auth;
  const { postId } = req.params;

  const oldSet = new Set<string>();
  const newSet = new Set<string>();

  const fileIdArr = new Array<Types.ObjectId>();

  const form = formidable({
    uploadDir: "uploads",
    keepExtensions: true,
    multiples: true,
  });

  form.parse(req, async (err, fields, files) => {
    if (!Array.isArray(fields.title)) {
      const title = fields.title;
      if (!Array.isArray(fields.text)) {
        const text = fields.text;
        if (!Array.isArray(fields.theme)) {
          const theme = fields.theme;
          if (!Array.isArray(fields.city)) {
            const city = fields.city;

            console.log("check files", files);

            if (files.picture === undefined || files.picture === null) {
              const postRes1 = await postDb.updatePostRow(
                {
                  title,
                  text,
                  theme,
                  city,
                  date: Date.now(),
                },
                postId
              );
              console.log("no files update", postRes1);
              return res.json(postRes1);
            } else {
              if (Array.isArray(files.picture)) {
                const oldFilesId = await postDb.getFilesByPostId(postId);
                if (!(oldFilesId === undefined)) {
                  for (var i = 0; i < oldFilesId?.length; i++) {
                    const name = await postDb.getOriginalFileName(
                      oldFilesId[i]
                    );
                    if (!(name === undefined)) {
                      oldSet.add(name);
                    }
                  }
                }
                console.log("OldSet", oldSet);

                if (Array.isArray(files.picture)) {
                  for (var i = 0; i < files.picture.length; i++) {
                    const newFileName = files.picture?.[i].originalFilename;
                    if (!(newFileName === undefined || newFileName === null)) {
                      newSet.add(newFileName);
                    }
                  }
                }
                console.log("NewSet", newSet);

                //유지, 삭제, 추가 구분하기
                const trdPart = SubTract(oldSet, newSet);

                console.log("keep", trdPart.keep);
                console.log("drop", trdPart.drop);
                console.log("add", trdPart.add);

                // 삭제
                for (var i = 0; i < trdPart.drop.length; i++) {
                  const dropRes = await postDb.deleteFileByName(
                    trdPart.drop[i]
                  );
                  console.log("delete counts", dropRes);
                }

                //유지
                for (var i = 0; i < trdPart.keep.length; i++) {
                  const keepRes = await postDb.findByName(trdPart.keep[i]);
                  fileIdArr.push(keepRes[0]._id);
                  // console.log("keep Id", keepRes[0]._id);
                }

                //추가
                for (var i = 0; i < files.picture.length; i++) {
                  const originalfilename = files.picture?.[i].originalFilename;
                  const newfilename = files.picture?.[i].newFilename;
                  const filepath = files.picture?.[i].filepath;
                  for (var j = 0; j < trdPart.add.length; j++) {
                    const check = trdPart.add[j];
                    if (originalfilename === check) {
                      const addRes = await postDb.createFilesRow(
                        originalfilename,
                        newfilename,
                        filepath
                      );

                      fileIdArr.push(addRes._id);
                    }
                  }
                }

                console.log("all fileId", fileIdArr);

                //post정보 + file정보 update
                const postRes2 = await postDb.updatePostRow(
                  {
                    title,
                    text,
                    theme,
                    city,
                    date: Date.now(),
                    file: fileIdArr,
                  },
                  postId
                );
                console.log("plural files update", postRes2);
                return res.json(postRes2);
              } else {
                const oldFilesId = await postDb.getFilesByPostId(postId);
                if (!(oldFilesId === undefined)) {
                  const name = await postDb.getOriginalFileName(oldFilesId[0]);
                  if (!(name === undefined)) {
                    oldSet.add(name);
                  }
                }
                console.log("OldSet", oldSet);

                const newFileName = files.picture.originalFilename;
                if (!(newFileName === undefined || newFileName === null)) {
                  newSet.add(newFileName);
                }
                console.log("NewSet", newSet);

                //유지, 삭제, 추가 구분하기
                const trdPart = SubTract(oldSet, newSet);

                console.log("add part", trdPart.add);

                //삭제
                for (var i = 0; i < trdPart.drop.length; i++) {
                  const dropRes = await postDb.deleteFileByName(
                    trdPart.drop[i]
                  );
                  console.log("delete counts", dropRes);
                }

                //추가
                const originalfilename = files.picture.originalFilename;
                const newfilename = files.picture.newFilename;
                const filepath = files.picture.filepath;
                if (originalfilename === trdPart.add[0]) {
                  const addRes = await postDb.createFilesRow(
                    originalfilename,
                    newfilename,
                    filepath
                  );

                  fileIdArr.push(addRes._id);
                }

                console.log("all fileId", fileIdArr);

                //post정보 + file정보 update
                const postRes3 = await postDb.updatePostRow(
                  {
                    title,
                    text,
                    theme,
                    city,
                    date: Date.now(),
                    file: fileIdArr,
                  },
                  postId
                );
                console.log("singular file update", postRes3);
                return res.json(postRes3);
              }
            }
          }
        }
      }
    }
  });
});

// Delete
export const deleteOnePost = asyncWrap(async (req, res) => {
  const { postId } = req.params;

  const deleteCount = await postDb.deletePost(postId);

  return res.json(deleteCount);
});
