const { Op } = require("sequelize");
const dbSAPPS = require("../../helpers/db");
require("dotenv").config();

module.exports = {
  getAll,
  filter,
  option,
  count,
  create,
  update,
  enabled,
  massUpdateCode,
  delete: _delete,
};

async function getAll(params) {
  try {
    const offset = (parseInt(params?.page) - 1) * parseInt(params?.limit);
    const whereClause = params?.search
      ? {
          [Op.or]: [
            { display_name: { [Op.iLike]: `%${params?.search}%` } },
            { code: { [Op.iLike]: `%${params?.search}%` } },
          ]
        }
      : {};

    const { count, rows } = await dbSAPPS.Client.findAndCountAll({
      where: whereClause,
      order: [["modified", "DESC"]],
      limit: parseInt(params?.limit),
      offset,
      include: [
        {
          model: dbSAPPS.ClientType,
          as: "clienttype",
          attributes: ["id", "display_name"]
        },
        {
          model: dbSAPPS.Specialist,
          as: "specialist",
          attributes: ["id", "display_name", "code"]
        },
        {
          model: dbSAPPS.SubSpecialist,
          as: "subspecialist",
          attributes: ["id", "display_name", "code"]
        },
        {
          model: dbSAPPS.ClientSubtype,
          as: "clientsubtype",
          attributes: ["id", "display_name", "code"]
        },
        {
          model: dbSAPPS.Province,
          as: "province",
          attributes: ["id", "display_name", "code"]
        },
        {
          model: dbSAPPS.City,
          as: "city",
          attributes: ["id", "display_name", "code"]
        }
      ]
    });

    return {
      success: true,
      message: "Clients loaded successfully",
      clients: rows,
      total: count
    };
  } catch (error) {
    console.error("Error fetching clients:", error);
    return {
      success: false,
      message: error.message || "Failed to load clients"
    };
  }
}

async function filter(params) {
  const filterConditions = {};

  if (params.display_name) {
    filterConditions.display_name = {
      [Op.like]: `%${params.display_name}%`,
    };
  }

  if (params.code) {
    filterConditions.code = {
      [Op.like]: `%${params.code}%`,
    };
  }


  if (params.clienttype_id) {
    filterConditions.clienttype_id = {
      [Op.like]: `%${params.clienttype_id}%`,
    };
  }
  
  if (params.province_id) {
    filterConditions.province_id = {
      [Op.like]: `%${params.province_id}%`,
    };
  }
  if (params.city_id) {
    filterConditions.city_id = {
      [Op.like]: `%${params.city_id}%`,
    };
  }
  if (params.specialist_id) {
    filterConditions.specialist_id = {
      [Op.like]: `%${params.specialist_id}%`,
    };
  }
  if (params.subspecialist_id) {
    filterConditions.subspecialist_id = {
      [Op.like]: `%${params.subspecialist_id}%`,
    };
  }
  if (params.clientsubtype_id) {
    filterConditions.clientsubtype_id = {
      [Op.like]: `%${params.clientsubtype_id}%`,
    };
  }

  if (params.enabled) {
    filterConditions.enabled = {
      [Op.eq]: params.enabled === "1" ? true : false,
    };
  }
  try {
    const clients = await dbSAPPS.Client.findAll({
      where: filterConditions,
      include: [
        {
          model: dbSAPPS.ClientType,
          as: "clienttype",
          attributes: ['id', 'display_name', 'code'],
        },
        {
          model: dbSAPPS.Specialist,
          as: "specialist",
          attributes: ['id', 'display_name', 'code'],
        },
        {
          model: dbSAPPS.SubSpecialist,
          as: "subspecialist",
          attributes: ['id', 'display_name', 'code'],
        },
        {
          model: dbSAPPS.ClientSubtype,
          as: "clientsubtype",
          attributes: ['id', 'display_name', 'code'],
        },
        {
          model: dbSAPPS.Province,
          as: "province",
          attributes: ['id', 'display_name', 'code'],
        },
        {
          model: dbSAPPS.City,
          as: "city",
          attributes: ['id', 'display_name', 'code'],
        },
      ]
    });

    const dataClients = await Promise.all(clients.map(async (item) => {
      const modifiedBy = await dbSAPPS.User.findOne({where: { id: parseInt(item.modified_by) }, attributes: ['full_name']});
      return {
        ...item.toJSON(),
        modifiedBy: modifiedBy ? modifiedBy.dataValues.full_name : null
      };
    }));


    return {
      clients: dataClients,
      success: true,
      message: "clients loaded successfully!",
    };
  } catch (error) {
    console.error("Error retrieving clients: ", error);
    const errorMessage =
      error.message || "Failed to retrieve clients. Please try again later.";
    // Mengembalikan respons dengan status 500 Internal Server Error
    return {
      success: false,
      message: errorMessage,
    };
  }
}

async function option() {
  try {
    const clients = await dbSAPPS.Client.findAll({
      attributes: ["id", "display_name", "code"],
      where: { enabled: true },
      order: [["display_name", "ASC"]], // Opsional: Mengurutkan hasil berdasarkan
    });

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

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

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

async function create(params) {
  try {
    if (!params.display_name) {
      return {
        success: false,
        message: "Clients name",
      };
    }

    console.log('params', params);

    const existingNameNNumber = await dbSAPPS.Client.findOne({
        where: {
          display_name: params.display_name,
        },
      });

    if (existingNameNNumber)
      return {
        success: false,
        message: `Client name "${params.display_name}" is already taken.`,
      };
    
    if (!params.enabled) params.enabled = true;


    // Ambil client terakhir untuk mendapatkan nomor urut terakhir
    // const lastClient = await dbSAPPS.Client.findOne({
    //   order: [['code', 'DESC']],
    // });

    // let lastIncrement = 1;
    // if (lastClient && lastClient.code) {
    //   lastIncrement = parseInt(lastClient.code.slice(-4), 10) + 1; // Ambil 4 digit terakhir dan tambahkan 1
    // }

    // const codeResult = await generateCode(params, lastIncrement);
    // if (!codeResult.success) {
    //   return codeResult; // Kembalikan jika ada kesalahan
    // }

    // params.code = codeResult.code;

    // const existingclientsCode = await dbSAPPS.Client.findOne({ where: { code: params.code } });
    // if (existingclientsCode) {
    //   return {
    //     success: false,
    //     message: `Client code "${params.code}" is already taken. Try again!`,
    //   };
    // }

    const newclients = await dbSAPPS.Client.create(params);

    return {
      success: true,  
      message: "clients data has been successfully added!",
      clients: newclients,
    };
  } catch (error) {
    const errorMessage = error.message || "An error occurred during create clients processing.";
    return {
      success: false,
      message: errorMessage,
    };
  }
}

async function generateCode(params, incrementValue) {
  try {
    let code = 'C';
    let proviceCode = '00', cityCode = '00', clientTypeCode = '00';
    let specialistCode = '00', subSpecialistCode = '00', clientSubTypeCode = '00';

    if (params.province_id) {
      const province = await dbSAPPS.Province.findByPk(params.province_id);
      proviceCode = province?.code || '00';
    }

    if (params.city_id) {
      const city = await dbSAPPS.City.findByPk(params.city_id);
      cityCode = city?.code || '00';
    }

    if (params.clienttype_id) {
      const clientType = await dbSAPPS.ClientType.findByPk(params.clienttype_id);
      clientTypeCode = clientType?.code || '00';
    }

    if (params.specialist_id) {
      const specialist = await dbSAPPS.Specialist.findByPk(params.specialist_id);
      specialistCode = specialist?.code || '00';
    }

    if (params.subspecialist_id) {
      const subSpecialist = await dbSAPPS.SubSpecialist.findByPk(params.subspecialist_id);
      subSpecialistCode = subSpecialist?.code || '00';
    }

    if (params.clientsubtype_id) {
      const clientSubtype = await dbSAPPS.ClientSubtype.findByPk(params.clientsubtype_id);
      clientSubTypeCode = clientSubtype?.code || '00';
    }

    // Gunakan nomor urut yang dikirim dari service massUpdateCode
    let increment4DigitAngka = incrementValue.toString().padStart(4, '0');

    const newCode =
      code +
      proviceCode +
      cityCode +
      clientTypeCode +
      specialistCode +
      subSpecialistCode +
      clientSubTypeCode +
      increment4DigitAngka;

    params.code = newCode;
    return { success: true, code: newCode };
  } catch (error) {
    console.error('Error generating code:', error);
    return { success: false, error: error.message };
  }
}


async function update(id, params) {
  try {
    const clients = await dbSAPPS.Client.findByPk(id);
    if (!clients)
      return {
        success: false,
        message: "clients not found!",
      };

    if (params.display_name && params.display_name !== clients.display_name) {
      const existingclientsName = await dbSAPPS.Client.findOne({
        where: { display_name: params.display_name },
      });
      if (existingclientsName) {
        return {
          success: false,
          message: `Client name "${params.display_name}" is already taken. Try again!`,
        };
      }
    }

    // const lastClient = await dbSAPPS.Client.findOne({
    //   order: [['code', 'DESC']],
    // });

    // let lastIncrement = 1;
    // if (lastClient && lastClient.code) {
    //   lastIncrement = parseInt(lastClient.code.slice(-4), 10) + 1; // Ambil 4 digit terakhir dan tambahkan 1
    // }


    //  // Generate code
    //  if (!params.code) {
    //    const codeResult = await generateCode(params, lastIncrement);
    //    if (!codeResult.success) {
    //      return codeResult; // Kembalikan jika ada kesalahan
    //    }
 
    //    params.code = codeResult.code;
    //  }
     

    // if (params.code && params.code !== clients.code) {
    //   const existingclientsCode = await dbSAPPS.Client.findOne({
    //     where: { code: params.code },
    //   });
    //   if (existingclientsCode) {
    //     return {
    //       success: false,
    //       message: `Clients code "${params.code}" is already taken. Try again!`,
    //     };
    //   }
    // }

    await clients.update(params);

    return {
      success: true,
      message: "Data clients has been saved!",
    };
  } catch (error) {
    const errorMessage = error.message || "Failed to update clients data.";
    return {
      success: false,
      message: errorMessage,
    };
  }
}

async function massUpdateCode(paramsArray) {
  const transaction = await dbSAPPS.sequelize.transaction();
  try {
    const clientIds = paramsArray.map((params) => params.id);

    // Ambil semua clients yang diperlukan dalam satu query
    const clients = await dbSAPPS.Client.findAll({
      where: { id: clientIds },
      transaction,
    });

    if (clients.length !== paramsArray.length) {
      throw new Error("Some clients were not found!");
    }

    // Mapping clients berdasarkan ID
    const clientsMap = new Map(clients.map((client) => [client.id, client]));

    // Ambil client terakhir untuk mendapatkan nomor urut terakhir
    const lastClient = await dbSAPPS.Client.findOne({
      order: [['code', 'DESC']],
      transaction,
    });

    let lastIncrement = 1;
    if (lastClient && lastClient.code) {
      lastIncrement = parseInt(lastClient.code.slice(-4), 10) + 1; // Ambil 4 digit terakhir dan tambahkan 1
    }

    for (const params of paramsArray) {
      const client = clientsMap.get(params.id);
      if (!client) {
        throw new Error(`Client with ID ${params.id} not found!`);
      }

      if (params.code && params.code !== client.code) {
        const existingClientCode = await dbSAPPS.Client.findOne({
          where: { code: params.code },
          transaction,
        });
        if (existingClientCode) {
          throw new Error(`Clients code "${params.code}" is already taken. Try again!`);
        }
      }

      // Gunakan lastIncrement yang dikelola dalam loop ini
      const codeResult = await generateCode(params, lastIncrement);
      if (!codeResult.success) {
        throw new Error(codeResult.error || "Error generating code");
      }

      params.code = codeResult.code;
      lastIncrement++; // Tambah nomor urut agar tidak duplikat

      await client.update(params, { transaction });
    }

    await transaction.commit();
    return {
      success: true,
      message: "All clients data have been successfully updated!",
    };
  } catch (error) {
    await transaction.rollback();
    return {
      success: false,
      message: error.message || "Failed to update clients data.",
    };
  }
}

async function enabled(id, params) {
  try {
    const clients = await dbSAPPS.Client.findByPk(id);
    if (!clients)
      return {
        success: false,
        message: "clients 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 clients.update(updateData);

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

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

    await clients.destroy();

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