const { logger } = require('../../middleware/logger');

class UserDocumentRepository {
  constructor(unitOfWork) {
    this.unitOfWork = unitOfWork;
  }

  _getConn() {
    const conn = this.unitOfWork && this.unitOfWork.connection;
    if (!conn) {
      const err = new Error('UnitOfWork connection is not available (was commit()/rollback() already called?)');
      err.code = 'UOW_CONNECTION_MISSING';
      throw err;
    }
    return conn;
  }

  async insertDocument({
    userId,
    documentType,
    contractType = 'contract',
    objectStorageId,
    signatureBase64 = null,
    originalFilename,
    fileSize,
    mimeType
  }) {
    logger.info('UserDocumentRepository.insertDocument:start', { userId, documentType, originalFilename });
    const conn = this._getConn();
    const query = `
      INSERT INTO user_documents (
        user_id, document_type, contract_type, object_storage_id, signatureBase64,
        original_filename, file_size, mime_type
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
    `;
    try {
      const [result] = await conn.query(query, [
        userId,
        documentType,
        contractType,
        objectStorageId,
        signatureBase64,
        originalFilename,
        fileSize,
        mimeType
      ]);
      logger.info('UserDocumentRepository.insertDocument:success', { userId, documentId: result.insertId });
      return result.insertId;
    } catch (error) {
      logger.error('UserDocumentRepository.insertDocument:error', { userId, error: error.message });
      throw error;
    }
  }

  async insertIdMetadata({ userDocumentId, idType, idNumber, expiryDate }) {
    logger.info('UserDocumentRepository.insertIdMetadata:start', { userDocumentId, idType, idNumber });
    const conn = this._getConn();
    try {
      await conn.query(
        `INSERT INTO user_id_documents (user_document_id, id_type, id_number, expiry_date)
         VALUES (?, ?, ?, ?)`,
        [userDocumentId, idType, idNumber, expiryDate]
      );
      logger.info('UserDocumentRepository.insertIdMetadata:success', { userDocumentId });
    } catch (error) {
      logger.error('UserDocumentRepository.insertIdMetadata:error', { userDocumentId, error: error.message });
      throw error;
    }
  }

  async insertIdDocument({
    userId,
    documentType,
    frontObjectStorageId,
    backObjectStorageId,
    idType,
    idNumber,
    expiryDate,
    originalFilenameFront,
    originalFilenameBack
  }) {
    logger.info('UserDocumentRepository.insertIdDocument:start', { userId, documentType, idType, idNumber });
    const conn = this._getConn();
    try {
      await conn.query(
        `INSERT INTO user_id_documents (
          user_id, document_type, front_object_storage_id, back_object_storage_id,
          original_filename_front, original_filename_back, id_type, id_number, expiry_date
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
        [
          userId,
          documentType,
          frontObjectStorageId,
          backObjectStorageId,
          originalFilenameFront || null,
          originalFilenameBack || null,
          idType,
          idNumber,
          expiryDate
        ]
      );
      logger.info('UserDocumentRepository.insertIdDocument:success', { userId });
    } catch (error) {
      logger.error('UserDocumentRepository.insertIdDocument:error', { userId, error: error.message });
      throw error;
    }
  }

  async getDocumentsForUser(userId) {
    logger.info('UserDocumentRepository.getDocumentsForUser:start', { userId });
    const conn = this._getConn();
    try {
      const [rows] = await conn.query(
        `SELECT * FROM user_documents WHERE user_id = ?`,
        [userId]
      );
      logger.info('UserDocumentRepository.getDocumentsForUser:success', { userId, count: rows.length });
      return rows;
    } catch (error) {
      logger.error('UserDocumentRepository.getDocumentsForUser:error', { userId, error: error.message });
      throw error;
    }
  }

  async getIdDocumentsForUser(userId) {
    logger.info('UserDocumentRepository.getIdDocumentsForUser:start', { userId });
    const conn = this._getConn();
    try {
      const [rows] = await conn.query(
        `SELECT * FROM user_id_documents WHERE user_id = ?`,
        [userId]
      );
      logger.info('UserDocumentRepository.getIdDocumentsForUser:success', { userId, count: rows.length });
      return rows;
    } catch (error) {
      logger.error('UserDocumentRepository.getIdDocumentsForUser:error', { userId, error: error.message });
      throw error;
    }
  }

  async getAllObjectStorageIdsForUser(userId) {
    logger.info('UserDocumentRepository.getAllObjectStorageIdsForUser:start', { userId });
    const conn = this._getConn();
    try {
      // Get object_storage_id from user_documents
      const [docRows] = await conn.query(
        `SELECT object_storage_id FROM user_documents WHERE user_id = ?`,
        [userId]
      );
      // Get front/back object_storage_id from user_id_documents
      const [idDocRows] = await conn.query(
        `SELECT front_object_storage_id, back_object_storage_id FROM user_id_documents WHERE user_id = ?`,
        [userId]
      );
      logger.info('UserDocumentRepository.getAllObjectStorageIdsForUser:success', { userId, count: docRows.length + idDocRows.length });
      return [...docRows, ...idDocRows];
    } catch (error) {
      logger.error('UserDocumentRepository.getAllObjectStorageIdsForUser:error', { userId, error: error.message });
      throw error;
    }
  }

  async deleteSignatureDocumentsForUser(userId) {
    logger.info('UserDocumentRepository.deleteSignatureDocumentsForUser:start', { userId });
    const conn = this._getConn();
    try {
      const [result] = await conn.query(
        `DELETE FROM user_documents WHERE user_id = ? AND document_type = 'signature'`,
        [userId]
      );
      logger.info('UserDocumentRepository.deleteSignatureDocumentsForUser:success', { userId, affectedRows: result.affectedRows });
      return result.affectedRows;
    } catch (error) {
      logger.error('UserDocumentRepository.deleteSignatureDocumentsForUser:error', { userId, error: error.message });
      throw error;
    }
  }
}

module.exports = UserDocumentRepository;
