import type { Request, Response } from "express";
import { AuthService } from "../services/AuthService.js";
import { createUploadMiddleware } from "../middleware/upload.middleware.js";
import path from "path";
import fs from "fs";
import { z } from "zod";

const baseUrl = process.env.BASE_URL || "baseurl not loaded check env";
const FILE_LOCATION = "uploads/profiles";
const uploadDir = path.join(process.cwd(), FILE_LOCATION);

const profileUpdateSchema = z.object({
  name: z.string().optional(),
  mobileNo: z.string().optional(),
  password: z.string().min(6, "Password must be at least 6 characters").optional(),
});

export class AuthController {
  constructor(private readonly authService = new AuthService()) { }

  handleImageUpload = createUploadMiddleware(FILE_LOCATION, "profile", "profile");

  login = async (req: Request, res: Response): Promise<void> => {
    try {
      const { email, password } = req.body;

      if (!email || !password) {
        res.status(400).json({ message: "Email and password are required." });
        return;
      }

      const result = await this.authService.login(email, password);
      //sends the profile pic in login response.

      if (result.user.status == false) {
        res.status(400).json({ message: "Your account is inactive. Please contact the administrator." });
        return;
      }

      res.status(200).json({
        ...result,
        user: {
          ...result.user,
          profileUrl: result.user.profile
            ? `${baseUrl}/${FILE_LOCATION}/${result.user.profile}`
            : null,
        },
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : "Login failed";
      res.status(412).json({ message });
    }
  };

  logout = async (_req: Request, res: Response): Promise<void> => {
    try {
      const result = await this.authService.logout();
      res.status(200).json(result);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Logout failed";
      res.status(500).json({ message });
    }
  };

  //Profile.
  getProfile = async (req: Request, res: Response): Promise<void> => {
    try {
      const userId = BigInt(req.user?.id || 0);
      const user = await this.authService.getProfile(userId);

      // Create a user object with the profileUrl appended
      const userData = {
        ...user,
        profileUrl: user.profile
          ? `${baseUrl}/${FILE_LOCATION}/${user.profile}`
          : null,
      };

      res.status(200).json(userData);
    } catch (error) {
      const message = error instanceof Error ? error.message : "Failed to get profile";
      res.status(500).json({ message });
    }
  };

  updateProfile = async (req: Request, res: Response): Promise<void> => {
    try {
      const parsedData = profileUpdateSchema.safeParse(req.body);

      if (!parsedData.success) {
        if (req.file) {
          if (fs.existsSync(req.file.path)) fs.unlinkSync(req.file.path);
        }

        const formattedErrors: Record<string, string> = {};
        parsedData.error.issues.forEach((issue) => {
          if (issue?.path && issue.path.length > 0 && issue.path[0] !== undefined) {
            formattedErrors[issue.path[0].toString()] = issue.message;
          }
        });

        res.status(422).json({
          message: "Validation failed",
          errors: Object.keys(formattedErrors).length > 0 ? formattedErrors : parsedData.error.issues,
        });
        return;
      }

      const { name, mobileNo, password } = parsedData.data;
      const userId = BigInt(req.user?.id || 0);
      const existingUser = await this.authService.getProfile(userId);

      let profileImage = existingUser?.profile ?? "default-profile.png";

      // New Profile Image Uploaded
      if (req.file) {
        // Delete previous uploaded profile image
        if (
          existingUser?.profile &&
          existingUser.profile !== "default-profile.png"
        ) {
          const oldProfile = path.join(uploadDir, existingUser.profile);
          if (fs.existsSync(oldProfile)) {
            fs.unlinkSync(oldProfile);
          }
        }
        profileImage = req.file.filename;
      }

      const updateData: any = { profile: profileImage };
      if (name && name.trim() !== "") updateData.name = name;
      if (mobileNo && mobileNo.trim() !== "") updateData.mobileNo = mobileNo;
      if (password && password.trim() !== "") updateData.password = password;

      const updatedProfile = await this.authService.updateProfile(userId, updateData);

      const { password: _pw, ...userWithoutPassword } = updatedProfile;

      res.status(200).json({
        ...userWithoutPassword,
        profileUrl: updatedProfile.profile
          ? `${baseUrl}/${FILE_LOCATION}/${updatedProfile.profile}`
          : null,
      });
    } catch (error: any) {
      // Delete uploaded file if DB fails
      if (req.file) {
        if (fs.existsSync(req.file.path)) {
          fs.unlinkSync(req.file.path);
        }
      }

      // Handle Prisma Unique Constraint Error
      if (error?.code === "P2002") {
        let fieldName = "Field";
        const target = error.meta?.target;

        if (Array.isArray(target)) {
          fieldName = target[0];
        } else if (typeof target === "string") {
          fieldName = target;
        }

        // Clean up table prefix and key suffix if it's a raw index name
        if (fieldName.includes("users_") && fieldName.includes("_key")) {
          fieldName = fieldName.replace("users_", "").replace("_key", "");
        }

        // Fallback to error message parsing if target was undefined
        if (fieldName === "Field" && error.message) {
          const match = error.message.match(/users_([a-zA-Z0-9_]+)_key/);
          if (match) {
            fieldName = match[1];
          } else if (error.message.includes("mobileNo")) {
            fieldName = "mobileNo";
          } else if (error.message.includes("email")) {
            fieldName = "email";
          }
        }

        res.status(422).json({
          message: "Validation failed",
          errors: {
            [fieldName]: `The ${fieldName} is already in use.`
          }
        });
        return;
      }

      const message = error instanceof Error ? error.message : "Failed to update profile";
      res.status(500).json({ message });
    }
  };
}
