// import type { Request, Response } from "express";
// import { catchAsyncError } from "./catchAsyncError";
// import database from "../config/db";
// import ErrorHandler from "./error";
// import jwt from "jsonwebtoken";

// export const isAuthenticated = catchAsyncError(async (req, res, next) => {
//   const { token } = req.cookies;

//   if (!token) {
//     return next(new ErrorHandler("Please login to access this resource.", 401));
//   }

//   const decoded = jwt.verify(token, process.env.JWT_SECRET_KEY as string);

//   const user = await database.query(
//     "SELECT * FROM users WHERE id = $1 LIMIT 1",
//     [(decoded as any).id]
//   );

//   req.user = user.rows[0];
//   next();
// });

// export const authorizedRoles = (...roles: string[]) => {
//   return (req: Request, res: Response, next: Function): void => {
//     if (!roles.includes(req.user?.role as string)) {
//       return next(
//         new ErrorHandler(
//           `Role: ${req.user?.role} is not allowed to access this resource.`,
//           403
//         )
//       );
//     }
//     next();
//   };
// };

// import { Request, Response, NextFunction } from "express";
// import { catchAsyncError } from "./catchAsyncError";
// import ErrorHandler from "./error";
// import { verifyToken } from "../utils/jwtToken";
// import database from "../config/db";

// export interface AuthRequest extends Request {
//   user?: any;
// }

// export const isAuthenticated = catchAsyncError(async (req: AuthRequest, res: Response, next: NextFunction) => {
//   const token = req.cookies.access_token || req.headers.authorization?.replace("Bearer ", "");

//   if (!token) {
//     return next(new ErrorHandler("Please login to access this resource.", 401));
//   }

//   try {
//     const decodedData = verifyToken(token);

//     // Fetch user from database
//     const result = await database.query(
//       `SELECT * FROM accounts WHERE id = $1 AND is_active = true AND account_status = 'active'`,
//       [decodedData.id]
//     );

//     if (result.rows.length === 0) {
//       return next(new ErrorHandler("User not found or account is inactive.", 401));
//     }

//     req.user = result.rows[0];
//     next();
//   } catch (error) {
//     return next(new ErrorHandler("Invalid or expired token.", 401));
//   }
// });

// // Middleware for company accounts only
// export const isCompany = catchAsyncError(async (req: AuthRequest, res: Response, next: NextFunction) => {
//   if (!req.user) {
//     return next(new ErrorHandler("Please login to access this resource.", 401));
//   }

//   if (req.user.account_type !== 'company') {
//     return next(new ErrorHandler("This resource is only available for company accounts.", 403));
//   }

//   next();
// });

// // Middleware for user accounts only
// export const isUser = catchAsyncError(async (req: AuthRequest, res: Response, next: NextFunction) => {
//   if (!req.user) {
//     return next(new ErrorHandler("Please login to access this resource.", 401));
//   }

//   if (req.user.account_type !== 'user') {
//     return next(new ErrorHandler("This resource is only available for user accounts.", 403));
//   }

//   next();
// });

// // Middleware for admin access (you can extend this later)
// export const isAdmin = catchAsyncError(async (req: AuthRequest, res: Response, next: NextFunction) => {
//   if (!req.user) {
//     return next(new ErrorHandler("Please login to access this resource.", 401));
//   }

//   // You can add admin role field later
//   // For now, you can use a simple check
//   if (req.user.username !== 'admin') {
//     return next(new ErrorHandler("Admin access required.", 403));
//   }

//   next();
// });

import { Request, Response, NextFunction } from "express";
import { catchAsyncError } from "./catchAsyncError";
import ErrorHandler from "./error";
import { verifyToken } from "../utils/jwtToken";
import database from "../config/db";

export interface AuthRequest extends Request {
  user?: any;
}

/**
 * Check authentication + attach user, roles & permissions
 */
export const isAuthenticated = catchAsyncError(
  async (req: AuthRequest, res: Response, next: NextFunction) => {
    const token =
      req.cookies?.access_token ||
      req.headers.authorization?.replace("Bearer ", "");

    if (!token) {
      return next(
        new ErrorHandler("Please login to access this resource.", 401),
      );
    }

    try {
      const decodedData: any = verifyToken(token);

      // Fetch base user
      const userResult = await database.query(
        `
        SELECT *
        FROM accounts
        WHERE id = $1
          AND is_active = true
          AND account_status = 'active'
        `,
        [decodedData.id],
      );

      if (userResult.rows.length === 0) {
        return next(
          new ErrorHandler("User not found or account is inactive.", 401),
        );
      }

      // Fetch roles & permissions in parallel
      const [rolesResult, permissionsResult] = await Promise.all([
        database.query(`SELECT * FROM get_user_roles($1)`, [decodedData.id]),
        database.query(`SELECT * FROM get_user_permissions($1)`, [
          decodedData.id,
        ]),
      ]);

      const userData = userResult.rows[0];

      userData.roles = rolesResult.rows;
      userData.permissions = permissionsResult.rows.map(
        (p: any) => p.permission_name,
      );

      req.user = userData;
      next();
    } catch (error) {
      return next(new ErrorHandler("Invalid or expired token.", 401));
    }
  },
);

/**
 * Company-only access
 */
export const isCompany = catchAsyncError(
  async (req: AuthRequest, res: Response, next: NextFunction) => {
    if (!req.user) {
      return next(
        new ErrorHandler("Please login to access this resource.", 401),
      );
    }

    if (req.user.account_type !== "company") {
      return next(
        new ErrorHandler(
          "This resource is only available for company accounts.",
          403,
        ),
      );
    }

    next();
  },
);

/**
 * User-only access
 */
export const isUser = catchAsyncError(
  async (req: AuthRequest, res: Response, next: NextFunction) => {
    if (!req.user) {
      return next(
        new ErrorHandler("Please login to access this resource.", 401),
      );
    }

    if (req.user.account_type !== "user") {
      return next(
        new ErrorHandler(
          "This resource is only available for user accounts.",
          403,
        ),
      );
    }

    next();
  },
);

/**
 * Admin-only access (temporary logic)
 * Later replace with RBAC permission check
 */
export const isAdmin = catchAsyncError(
  async (req: AuthRequest, res: Response, next: NextFunction) => {
    if (!req.user) {
      return next(
        new ErrorHandler("Please login to access this resource.", 401),
      );
    }

    const isAdminRole = req.user.roles?.some(
      (role: any) => role.name === "admin" || role.name === "super_admin",
    );

    if (!isAdminRole) {
      return next(new ErrorHandler("Admin access required.", 403));
    }

    next();
  },
);

export const hasPermission = (permission: string) =>
  catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      if (!req.user?.permissions?.includes(permission)) {
        return next(
          new ErrorHandler(
            "You do not have permission to perform this action.",
            403,
          ),
        );
      }
      next();
    },
  );

export const hasMinLevel = (minLevel: number) =>
  catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const userLevels = req.user?.roles?.map((role: any) => role.level) || [];
      const highestLevel = Math.max(...userLevels, 0);

      if (highestLevel < minLevel) {
        return next(
          new ErrorHandler(
            "You do not have sufficient level to perform this action.",
            403,
          ),
        );
      }
      next();
    },
  );


export const hasAnyPermission = (permissions: string[]) =>
  catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const userPermissions = req.user?.permissions || [];
      const hasPermission = permissions.some((perm) =>
        userPermissions.includes(perm),
      );
      if (!hasPermission) {
        return next(
          new ErrorHandler(
            "You do not have permission to perform this action.",
            403,
          ),
        );
      }
      next();
    },
  );

export const canModifyResource = (
  resourceType: string,
  updatePermission: string,
  deletePermission: string,
  ownerField: string,
) =>
  catchAsyncError(
    async (req: AuthRequest, res: Response, next: NextFunction) => {
      const resourceId = req.params.id;
      const userId = req.user?.id;
      const userPermissions = req.user?.permissions || [];

      // Check if user has update or delete permission
      const hasUpdatePermission = userPermissions.includes(updatePermission);
      const hasDeletePermission = userPermissions.includes(deletePermission);
      if (hasUpdatePermission || hasDeletePermission) {
        return next();
      }
      // Fetch resource to check ownership
      const resourceResult = await database.query(
        `SELECT * FROM ${resourceType}s WHERE id = $1`,
        [resourceId],
      );
      if (resourceResult.rows.length === 0) {
        return next(new ErrorHandler(`${resourceType} not found.`, 404));
      }
      const resource = resourceResult.rows[0];

      // Check if user is the owner
      if (resource[ownerField] !== userId) {
        return next(
          new ErrorHandler(
            "You do not have permission to modify this resource.",
            403,
          ),
        );
      }
      next();
    },
  );
