import fs from "fs";
import path from "path";
import multer from "multer";
import { Router } from "express";
import { z } from "zod";
import { requireAuth, requireRoles } from "@/middleware/auth";
import { AppError, asyncHandler } from "@/lib/errors";
import { User } from "@/db/models";
import { createId } from "@/db/ids";
import { isAuthMysql } from "@/db/activeDatabase";
import { findUserByIdMysql, updateUserMysql } from "@/db/mysql/users";

const uploadsRoot = path.join(process.cwd(), "public", "uploads");
const dirs = {
  images: path.join(uploadsRoot, "images"),
  videos: path.join(uploadsRoot, "videos"),
  docs: path.join(uploadsRoot, "docs"),
};

for (const dir of Object.values(dirs)) {
  fs.mkdirSync(dir, { recursive: true });
}

function storageFor(folder: keyof typeof dirs) {
  return multer.diskStorage({
    destination: (_req, _file, cb) => cb(null, dirs[folder]),
    filename: (_req, file, cb) => {
      const ext = path.extname(file.originalname).toLowerCase() || ".bin";
      cb(null, `${createId()}${ext}`);
    },
  });
}

const imageUpload = multer({
  storage: storageFor("images"),
  limits: { fileSize: 8 * 1024 * 1024 },
  fileFilter: (_req, file, cb) => {
    if (!file.mimetype.startsWith("image/")) {
      return cb(new Error("Only image files are allowed"));
    }
    cb(null, true);
  },
});

const videoUpload = multer({
  storage: storageFor("videos"),
  limits: { fileSize: 60 * 1024 * 1024 },
  fileFilter: (_req, file, cb) => {
    if (!file.mimetype.startsWith("video/")) {
      return cb(new Error("Only video files are allowed"));
    }
    cb(null, true);
  },
});

const docUpload = multer({
  storage: storageFor("docs"),
  limits: { fileSize: 10 * 1024 * 1024 },
  fileFilter: (_req, file, cb) => {
    const ok =
      file.mimetype.startsWith("image/") ||
      file.mimetype === "application/pdf";
    if (!ok) return cb(new Error("Only image or PDF documents are allowed"));
    cb(null, true);
  },
});

export const uploadsRouter = Router();

uploadsRouter.post(
  "/images",
  requireAuth,
  requireRoles("OWNER", "ADMIN"),
  (req, res, next) => {
    imageUpload.array("files", 12)(req, res, (err) => {
      if (err) return next(new AppError(400, err.message || "Upload failed"));
      next();
    });
  },
  asyncHandler(async (req, res) => {
    const files = (req.files as Express.Multer.File[]) || [];
    if (!files.length) throw new AppError(400, "No files uploaded");
    res.status(201).json({
      files: files.map((f, i) => ({
        url: `/uploads/images/${f.filename}`,
        sortOrder: i,
      })),
    });
  }),
);

uploadsRouter.post(
  "/videos",
  requireAuth,
  requireRoles("OWNER", "ADMIN"),
  (req, res, next) => {
    videoUpload.array("files", 3)(req, res, (err) => {
      if (err) return next(new AppError(400, err.message || "Upload failed"));
      next();
    });
  },
  asyncHandler(async (req, res) => {
    const files = (req.files as Express.Multer.File[]) || [];
    if (!files.length) throw new AppError(400, "No files uploaded");
    res.status(201).json({
      files: files.map((f, i) => ({
        url: `/uploads/videos/${f.filename}`,
        sortOrder: i,
      })),
    });
  }),
);

uploadsRouter.post(
  "/passport",
  requireAuth,
  requireRoles("OWNER", "ADMIN"),
  (req, res, next) => {
    docUpload.single("file")(req, res, (err) => {
      if (err) return next(new AppError(400, err.message || "Upload failed"));
      next();
    });
  },
  asyncHandler(async (req, res) => {
    if (!req.file) throw new AppError(400, "No file uploaded");
    const passportUrl = `/uploads/docs/${req.file.filename}`;

    if (isAuthMysql()) {
      const user = await updateUserMysql(req.user!.id, {
        passportUrl,
        ownerVerificationStatus: "PENDING",
        trustedOwner: false,
      });
      if (!user) throw new AppError(404, "User not found");
      res.status(201).json({
        passportUrl,
        ownerVerificationStatus: user.ownerVerificationStatus,
        trustedOwner: Boolean(user.trustedOwner),
        message: "Passport uploaded — awaiting admin review",
        _db: "mysql",
      });
      return;
    }

    const user = await User.findByIdAndUpdate(
      req.user!.id,
      {
        $set: {
          passportUrl,
          ownerVerificationStatus: "PENDING",
          trustedOwner: false,
        },
      },
      { new: true },
    );
    if (!user) throw new AppError(404, "User not found");
    res.status(201).json({
      passportUrl,
      ownerVerificationStatus: user.ownerVerificationStatus,
      trustedOwner: Boolean(user.trustedOwner),
      message: "Passport uploaded — awaiting admin review",
      _db: "mongodb",
    });
  }),
);

uploadsRouter.get(
  "/verification-status",
  requireAuth,
  requireRoles("OWNER", "ADMIN"),
  asyncHandler(async (req, res) => {
    if (isAuthMysql()) {
      const user = await findUserByIdMysql(req.user!.id);
      if (!user) throw new AppError(404, "User not found");
      res.json({
        passportUrl: user.passportUrl ?? null,
        ownerVerificationStatus: user.ownerVerificationStatus ?? "NONE",
        trustedOwner: Boolean(user.trustedOwner),
        ownerVerifiedAt: user.ownerVerifiedAt ?? null,
        _db: "mysql",
      });
      return;
    }
    const user = await User.findById(req.user!.id)
      .select("passportUrl ownerVerificationStatus trustedOwner ownerVerifiedAt")
      .lean();
    if (!user) throw new AppError(404, "User not found");
    res.json({
      passportUrl: user.passportUrl ?? null,
      ownerVerificationStatus: user.ownerVerificationStatus ?? "NONE",
      trustedOwner: Boolean(user.trustedOwner),
      ownerVerifiedAt: user.ownerVerifiedAt ?? null,
      _db: "mongodb",
    });
  }),
);
