const { Op } = require("sequelize");
const dbSAPPS = require("../../helpers/db");
const bcrypt = require("bcryptjs");
const userService = require("../users/user.service");
require("dotenv").config();

module.exports = {
  getAll,
  option,
  count,
  create,
  update,
  enabled,
  delete: _delete,
  registerTenderVendor,
  getByUserId,
};
const formatWithModifier = async (tenderVendors) => {
  return Promise.all(
    tenderVendors.map(async (tenderVendor) => {
      const modifier = await dbSAPPS.User.findOne({
        where: {
          id: tenderVendor.modified_by,
        },
        attributes: ["full_name"],
      });

      return {
        ...tenderVendor,
        modifier: modifier?.full_name,
      };
    })
  );
};

async function getAll(params) {
  try {
    // filter
    const filterConditions = {};
    let tenderVendors = [];
    tenderVendors = await dbSAPPS.TenderVendor.findAll({
      where: filterConditions,
      order: [["modified", "DESC"]],
      include: [
        {
          model: dbSAPPS.TenderVendorFile,
          as: "tendervendorfile",
          attributes: ["id", "nib_file", "npwp_file", "siup_file", "sertifikat_file", "tendervendor_id"],
        },
      ],
    });

    tenderVendors = tenderVendors.map((tenderVendor) => {
      return {
        ...tenderVendor.dataValues
      };
    });

    tenderVendors = await formatWithModifier(tenderVendors);

    return {
      tenderVendors,
      success: true,
      message: "Tender vendor loaded successfully!",
    };
  } catch (error) {
    const errorMessage = error.message || "Failed to load tender vendor!";
    return {
      success: false,
      message: errorMessage,
    };
  }
}

async function option(params) {
  try {
    const tenderVendors = await dbSAPPS.TenderVendor.findAll({
      attributes: ["id", "vendor_name", "email"],
      where: { enabled: true },
      order: [["vendor_name", "ASC"]],
    });

    return {
      success: true,
      tenderVendors,
      message: "Tender vendor loaded successfully!",
    };
  } catch (error) {
    console.error("Error retrieving Tender vendor: ", error);
    const errorMessage =
      error.message || "Failed to retrieve Tender vendor. Please try again later.";
    return {
      success: false,
      message: errorMessage,
    };
  }
}

async function count(params) {
  try {
    const count = await dbSAPPS.TenderVendor.count({
      where: { enabled: true },
    });

    return {
      success: true,
      count,
      message: "Tender vendor count loaded successfully!",
    };
  } catch (error) {
    console.error("Error counting Tender vendor: ", error);
    return {
      success: false,
      message: "Failed to retrieve tenderVendors count. Please try again later.",
    };
  }
}

async function create(params) {
  const transaction = await dbSAPPS.sequelize.transaction();
  try {
    // Validate required fields
    if (!params.vendor_name) {
      return {
        success: false,
        message: "Nama perusahaan harus diisi!",
      };
    }

    if (!params.email) {
      return {
        success: false,
        message: "Email harus diisi!",
      };
    }

    // Validate existing vendor name
    const existingVendorName = await dbSAPPS.TenderVendor.findOne({
      where: { vendor_name: params.vendor_name },
      transaction,
    });
    if (existingVendorName) {
      return {
        success: false,
        message: `Nama perusahaan "${params.vendor_name}" sudah digunakan.`,
      };
    }

    // Validate existing email
    const existingEmail = await dbSAPPS.TenderVendor.findOne({
      where: { email: params.email },
      transaction,
    });
    if (existingEmail) {
      return {
        success: false,
        message: `Email "${params.email}" sudah digunakan.`,
      };
    }

    // Handle category - ensure it's JSON format
    if (params.category && typeof params.category === 'object') {
      params.category = JSON.stringify(params.category);
    }

    if (!params.enabled) params.enabled = true;
    if (!params.status) params.status = 'pending';

    // save
    await dbSAPPS.TenderVendor.create(params, { transaction });

    await transaction.commit();
    return {
      success: true,
      message: "Data vendor berhasil disimpan!",
    };
  } catch (error) {
    await transaction.rollback();
    const errorMessage = error?.message || "Gagal menyimpan data, silakan coba lagi!";
    return {
      success: false,
      message: errorMessage,
    };
  }
}

async function update(id, params) {
  try {
    const tenderVendor = await dbSAPPS.TenderVendor.findByPk(id);
    if (!tenderVendor)
      return {
        success: false,
        message: "Vendor tidak ditemukan!",
      };

    // Validate vendor_name if changed
    if (params.vendor_name && params.vendor_name !== tenderVendor.vendor_name) {
      const existingVendorName = await dbSAPPS.TenderVendor.findOne({
        where: { vendor_name: params.vendor_name },
      });
      if (existingVendorName) {
        return {
          success: false,
          message: `Nama perusahaan "${params.vendor_name}" sudah digunakan.`,
        };
      }
    }

    // Validate email if changed
    if (params.email && params.email !== tenderVendor.email) {
      const existingEmail = await dbSAPPS.TenderVendor.findOne({
        where: { email: params.email },
      });
      if (existingEmail) {
        return {
          success: false,
          message: `Email "${params.email}" sudah digunakan.`,
        };
      }
    }

    // Handle category - ensure it's JSON format
    if (params.category && typeof params.category === 'object') {
      params.category = JSON.stringify(params.category);
    }

    await tenderVendor.update(params);

    return {
      success: true,
      message: "Data vendor berhasil diperbarui!",
    };
  } catch (error) {
    const errorMessage = error.message || "Gagal memperbarui data vendor.";
    return {
      success: false,
      message: errorMessage,
    };
  }
}

async function enabled(id, params) {
  try {
    const tenderVendor = await dbSAPPS.TenderVendor.findByPk(id);
    if (!tenderVendor)
      return {
        success: false,
        message: "Tender vendor not found!",
      };

    const updateData = {};
    updateData.enabled = params.enabled;
    if (params.modified_by) updateData.modified_by = params.modified_by;
    if (params.modified) updateData.modified = params.modified;

    await tenderVendor.update(updateData);

    return {
      success: true,
      message: "Tender vendor has been updated!",
    };
  } catch (error) {
    const errorMessage = error.message || "Failed to update tender vendor.";
    return {
      success: false,
      message: errorMessage,
    };
  }
}

async function _delete(id) {
  try {
    const tenderVendor = await dbSAPPS.TenderVendor.findByPk(id);
    if (!tenderVendor) return { success: false, message: "Tender vendor not found!" };

    await tenderVendor.destroy();

    return {
      success: true,
      message: "Tender vendor successfully deleted!",
    };
  } catch (error) {
    const errorMessage = error.message || "Failed to delete tender vendor.";
    return {
      success: false,
      message: errorMessage,
    };
  }
}

async function getByUserId(userId) {
  try {
    const tenderVendor = await dbSAPPS.TenderVendor.findOne({
      where: { user_id: userId },
      attributes: ["id", "vendor_name", "email", "user_id"],
    });

    if (!tenderVendor) {
      return {
        success: false,
        message: "Tender vendor not found for this user!",
      };
    }

    return {
      success: true,
      tenderVendor: tenderVendor.dataValues,
      message: "Tender vendor loaded successfully!",
    };
  } catch (error) {
    const errorMessage = error.message || "Failed to load tender vendor!";
    return {
      success: false,
      message: errorMessage,
    };
  }
}

/**
 * Register a new tender vendor with user account and files
 * This function creates user, tender vendor, and files, then auto-logs in the user
 */
async function registerTenderVendor(params, files) {
  const transaction = await dbSAPPS.sequelize.transaction();
  try {
    // Validate required fields
    if (!params.user_email || !params.username || !params.password) {
      return {
        success: false,
        message: "Email, username, and password are required!",
      };
    }

    if (!params.vendor_name || !params.email || !params.phone || !params.address) {
      return {
        success: false,
        message: "Vendor name, email, phone, and address are required!",
      };
    }

    // Check if user email already exists
    const existingEmail = await dbSAPPS.User.findOne({
      where: { email: params.user_email },
      attributes: ["id"],
    });
    if (existingEmail) {
      return {
        success: false,
        message: `Email "${params.user_email}" is already taken.`,
      };
    }

    // Check if vendor email already exists
    const existingVendorEmail = await dbSAPPS.TenderVendor.findOne({
      where: { email: params.email },
      attributes: ["id"],
    });
    if (existingVendorEmail) {
      return {
        success: false,
        message: `Vendor email "${params.email}" is already registered.`,
      };
    }

    // Create user account
    const userData = {
      email: params.user_email,
      username: params.username,
      password: params.password,
      full_name: params.full_name,
      phone_number: params.phone_number,
      mobile_no: params.phone_number,
      role_id: 85, // Default role for tender vendor
      enabled: true,
      login_method: params.login_method || "email",
    };

    // Hash password
    const hash = await bcrypt.hash(userData.password, 10);
    userData.hash = hash;
    userData.secret = userData.password;

    // Default params for user
    userData.creation = Date.now();
    userData.modified = Date.now();
    userData.modified_by = 4 || 24;
    userData.owner = 4 || 24;
    userData.last_login = Date.now();

    // Create user
    const user = await dbSAPPS.User.create(userData, { transaction });

    if (!user?.id) {
      await transaction.rollback();
      return {
        success: false,
        message: "Failed to create user account!",
      };
    }

    // Create tender vendor
    const vendorData = {
      vendor_name: params.vendor_name,
      email: params.email,
      phone: params.phone,
      address: params.address,
      pic_name: params.pic_name,
      pic_phone: params.pic_phone,
      pic_email: params.pic_email,
      vendor: params.vendor || null,
      status: "pending", // Default status
      user_id: user.id,
      enabled: true,
      creation: Date.now(),
      modified: Date.now(),
      modified_by: user.id,
      owner: user.id,
    };

    const tenderVendor = await dbSAPPS.TenderVendor.create(vendorData, { transaction });

    if (!tenderVendor?.id) {
      await transaction.rollback();
      return {
        success: false,
        message: "Failed to create tender vendor!",
      };
    }

    // Create tender vendor files
    const fileData = {
      tendervendor_id: tenderVendor.id,
      nib_file: files.nib_file ? files.nib_file.filename : null,
      npwp_file: files.npwp_file ? files.npwp_file.filename : null,
      siup_file: files.siup_file ? files.siup_file.filename : null,
      sertifikat_file: files.sertifikat_file ? files.sertifikat_file.filename : null,
      enabled: true,
      creation: Date.now(),
      modified: Date.now(),
      modified_by: user.id,
      owner: user.id,
    };

    await dbSAPPS.TenderVendorFile.create(fileData, { transaction });

    // Commit transaction
    await transaction.commit();

    // Auto-login: Authenticate the user and return token
    const authResult = await userService.authenticate({
      email: params.user_email,
      password: params.password,
      loginMethod: params.login_method || "email",
    });

    if (!authResult.success) {
      return {
        success: false,
        message: "Registration successful but auto-login failed. Please login manually.",
      };
    }

    return {
      success: true,
      message: "Registration successful!",
      user: authResult.user,
      serviceToken: authResult.serviceToken,
      refreshToken: authResult.refreshToken,
      menus: authResult.menus,
      permissions: authResult.permissions,
      companies: authResult.companies,
      projects: authResult.projects,
      companiesId: authResult.companiesId,
      usersId: authResult.usersId,
      userProjectIds: authResult.userProjectIds,
      userCompanyIds: authResult.userCompanyIds,
      users: authResult.users,
      usertype: authResult.usertype,
    };
  } catch (error) {
    await transaction.rollback();
    console.error("Error registering tender vendor:", error);
    const errorMessage = error?.message || "Failed to register, please try again!";
    
    // Check if validation error
    if (error?.errors?.length > 0) {
      const validationErrors = error.errors.map((err) => err.message).join(", ");
      return {
        success: false,
        message: validationErrors,
      };
    }

    return {
      success: false,
      message: errorMessage,
    };
  }
}
