const UnitOfWork = require('../../database/UnitOfWork');
const UserRepository = require('../../repositories/user/UserRepository');
const { s3 } = require('../../utils/exoscaleUploader');
const { GetObjectCommand } = require('@aws-sdk/client-s3');
const { getSignedUrl } = require('@aws-sdk/s3-request-presigner');
const { logger } = require('../../middleware/logger'); // fixed import

class UserController {
  static async getMe(req, res) {
    const userId = req.user.userId;
    const unitOfWork = new UnitOfWork();
    await unitOfWork.start();
    try {
      logger.info(`[UserController] getMe called for userId: ${userId}`);
      const userRepo = new UserRepository(unitOfWork);
      const user = await userRepo.findUserByEmailOrId(userId);
      if (!user) {
        await unitOfWork.commit();
        logger.warn(`[UserController] User not found: ${userId}`);
        return res.status(404).json({ success: false, message: 'User not found' });
      }
      const iban = await userRepo.getIban(userId);
      const profile = await userRepo.getProfile(userId, user.userType);
      const referralEmail = await userRepo.getReferralEmail(userId, user.userType);

      await unitOfWork.commit();
      logger.info(`[UserController] getMe success for userId: ${userId}`);
      res.json({
        success: true,
        user: { ...user.getPublicData(), iban, referralEmail },
        profile
      });
    } catch (error) {
      await unitOfWork.rollback(error);
      logger.error(`[UserController] getMe error for userId: ${userId}`, { error });
      res.status(500).json({ success: false, message: error.message });
    }
  }

  static async getFullUserData(req, res) {
    const userId = req.params.id;
    const unitOfWork = new UnitOfWork();
    await unitOfWork.start();
    try {
      logger.info(`[UserController] getFullUserData called for userId: ${userId}`);
      const userRepo = new UserRepository(unitOfWork);
      const user = await userRepo.findUserByEmailOrId(Number(userId));
      if (!user) {
        await unitOfWork.commit();
        logger.warn(`[UserController] User not found: ${userId}`);
        return res.status(404).json({ success: false, message: 'User not found' });
      }
      const iban = await userRepo.getIban(userId);
      const profile = await userRepo.getProfile(userId, user.userType);
      const referralEmail = await userRepo.getReferralEmail(userId, user.userType);
      const permissions = await userRepo.getPermissions(userId);
      const userStatus = await userRepo.getUserStatus(userId);

      await unitOfWork.commit();
      logger.info(`[UserController] getFullUserData success for userId: ${userId}`);
      res.json({
        success: true,
        user: { ...user.getPublicData(), referralEmail, iban },
        profile,
        permissions,
        userStatus
      });
    } catch (error) {
      await unitOfWork.rollback(error);
      logger.error(`[UserController] getFullUserData error for userId: ${userId}`, { error });
      res.status(500).json({ success: false, message: error.message });
    }
  }

  static async getUserDocumentsAndContracts(req, res) {
    const requestedUserId = Number(req.params.id);
    const requesterUserId = req.user.userId;
    const requesterRole = req.user.role;

    if (requestedUserId !== requesterUserId && requesterRole !== 'admin' && requesterRole !== 'super_admin') {
      logger.warn(`[UserController] Forbidden access to documents for userId: ${requestedUserId} by userId: ${requesterUserId}`);
      return res.status(403).json({ success: false, message: 'Forbidden' });
    }

    const unitOfWork = new UnitOfWork();
    await unitOfWork.start();
    try {
      logger.info(`[UserController] getUserDocumentsAndContracts called for userId: ${requestedUserId}`);
      const userRepo = new UserRepository(unitOfWork);

      // Use repository methods instead of direct queries
      const contracts = await userRepo.getContracts(requestedUserId);
      const idDocs = await userRepo.getIdDocuments(requestedUserId);

      // Signed URLs for contracts (no Content-Disposition header)
      const contractsWithUrls = await Promise.all(
        contracts.map(async doc => {
          let signedUrl = null;
          if (doc.object_storage_id) {
            try {
              const command = new GetObjectCommand({
                Bucket: process.env.EXOSCALE_BUCKET,
                Key: doc.object_storage_id
              });
              signedUrl = await getSignedUrl(s3, command, { expiresIn: 900 });
            } catch (err) {
              signedUrl = null;
            }
          }
          return { ...doc, signedUrl };
        })
      );

      // Signed URLs for front/back of ID documents (with Content-Disposition header)
      const idDocFiles = await Promise.all(
        idDocs.flatMap(doc => [
          (async () => {
            let signedUrl = null;
            if (doc.front_object_storage_id) {
              try {
                const command = new GetObjectCommand({
                  Bucket: process.env.EXOSCALE_BUCKET,
                  Key: doc.front_object_storage_id,
                  ResponseContentDisposition: `attachment; filename="${doc.original_filename_front}"`
                });
                signedUrl = await getSignedUrl(s3, command, { expiresIn: 900 });
              } catch (err) {
                signedUrl = null;
              }
            }
            return {
              user_id_document_id: doc.id,
              user_id: doc.user_id,
              document_type: doc.document_type,
              side: 'front',
              object_storage_id: doc.front_object_storage_id,
              signedUrl,
              id_type: doc.id_type,
              id_number: doc.id_number,
              expiry_date: doc.expiry_date,
              original_filename: doc.original_filename_front
            };
          })(),
          (async () => {
            let signedUrl = null;
            if (doc.back_object_storage_id) {
              try {
                const command = new GetObjectCommand({
                  Bucket: process.env.EXOSCALE_BUCKET,
                  Key: doc.back_object_storage_id,
                  ResponseContentDisposition: `attachment; filename="${doc.original_filename_back}"`
                });
                signedUrl = await getSignedUrl(s3, command, { expiresIn: 900 });
              } catch (err) {
                signedUrl = null;
              }
            }
            return {
              user_id_document_id: doc.id,
              user_id: doc.user_id,
              document_type: doc.document_type,
              side: 'back',
              object_storage_id: doc.back_object_storage_id,
              signedUrl,
              id_type: doc.id_type,
              id_number: doc.id_number,
              expiry_date: doc.expiry_date,
              original_filename: doc.original_filename_back
            };
          })()
        ])
      );

      await unitOfWork.commit();
      logger.info(`[UserController] getUserDocumentsAndContracts success for userId: ${requestedUserId}`);
      res.json({
        success: true,
        contracts: contractsWithUrls,
        idDocuments: idDocFiles
      });
    } catch (error) {
      await unitOfWork.rollback(error);
      logger.error(`[UserController] getUserDocumentsAndContracts error for userId: ${requestedUserId}`, { error });
      res.status(500).json({ success: false, message: error.message });
    }
  }
}

module.exports = UserController;