/*
 * File: src/main/java/purchase/service/SupplierService.java
 * Description: This service class manages operations related to Supplier entities
 * within the ERP purchase module. It provides functionality to create, retrieve,
 * update, and delete suppliers while ensuring data integrity and adherence to
 * business rules. The service interacts with various repositories to perform CRUD
 * operations and utilizes JWT for authorization checks. Key functionalities include:
 *
 * - **createSupplier**: Validates the incoming SupplierRequest, ensuring all required
 *   fields are provided, and saves a new Supplier entity to the database.
 *
 * - **getSupplierById**: Retrieves a specific Supplier by its ID, returning an
 *   Optional Supplier object, or an exception if not found.
 *
 * - **getAllSuppliers**: Fetches a paginated list of all Suppliers associated
 *   with the requesting tenant.
 *
 * - **updateSupplier**: Updates an existing Supplier based on the provided
 *   SupplierRequest, ensuring that the requesting tenant matches the supplier's tenant.
 *
 * - **deleteSupplier**: Deletes a Supplier by its ID after validating that the
 *   requesting tenant matches the supplier's tenant, and checks for associated
 *   purchases or GRNs before deletion.
 *
 * - **existsByPurchases**: Checks if a Supplier has any associated purchases.
 *
 * - **existsByGrns**: Checks if a Supplier has any associated GRNs.
 *
 * This service encapsulates business logic related to Supplier management, ensuring
 * data consistency and compliance with tenant isolation principles while leveraging
 * Spring's dependency injection for accessing repositories and utilities.
 */

package com.nebula.erp.purchase.service;

import com.nebula.erp.purchase.model.Supplier;
import com.nebula.erp.purchase.repository.GRNRepository;
import com.nebula.erp.purchase.repository.PurchaseRepository;
import com.nebula.erp.purchase.repository.SupplierRepository;
import com.nebula.erp.purchase.requestmodel.SupplierRequest;
import com.nebula.erp.purchase.utility.CreateLogger;
import com.nebula.erp.purchase.utility.JwtRequestUtils;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.Optional;
import org.springframework.data.domain.Sort;

@Service
public class SupplierService {

    @Autowired
    private SupplierRepository supplierRepository;

    @Autowired
    private PurchaseRepository purchaseRepository;

    @Autowired
    private GRNRepository grnRepository;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private JwtRequestUtils jwtRequestUtils;

    @Autowired
    private CreateLogger createLogger;

    private static final String path = "/suppliers";

    public Supplier createSupplier(SupplierRequest supplierRequest) {

        String tenantName = jwtRequestUtils.getTenantName();
        String userId = jwtRequestUtils.getUserId();

        Supplier supplier = new Supplier();
        supplier.setSupplier_id(supplierRequest.getSupplier_id());
        supplier.setSupplier_name(supplierRequest.getSupplier_name());
        supplier.setContact_person(supplierRequest.getContact_person());
        supplier.setPhone_number(supplierRequest.getPhone_number());
        supplier.setEmail_address(supplierRequest.getEmail_address());
        supplier.setAddress(supplierRequest.getAddress());
        supplier.setCity(supplierRequest.getCity());
        supplier.setState_province(supplierRequest.getState_province());
        supplier.setZip_postal_code(supplierRequest.getZip_postal_code());
        supplier.setCountry(supplierRequest.getCountry());
        supplier.setWebsite(supplierRequest.getWebsite());
        supplier.setSupplier_type(supplierRequest.getSupplier_type());
        supplier.setNotes(supplierRequest.getNotes());
        supplier.setCreated_by(userId);
        supplier.setTenant(tenantName);

        // Save the supplier and return the result
        return supplierRepository.save(supplier);
    }

    public Optional<Supplier> getSupplierById(Long id) {
        return supplierRepository.findById(id);
    }

    public Page<Supplier> getAllSuppliers(int page, int size, String search) {

        Pageable pageable = PageRequest.of(
                page - 1,
                size,
                Sort.by(Sort.Direction.DESC, "created_at"));

        String tenant = jwtRequestUtils.getTenantName();

        // No length restriction
        if (search == null || search.trim().isEmpty()) {
            return supplierRepository.findAllByTenant(tenant, pageable);
        }

        String keyword = "%" + search.trim().toLowerCase() + "%";

        return supplierRepository.searchSuppliers(tenant, keyword, pageable);
    }

    // Get suppliers count
    public Integer getSuppliersCount(String tenant_name) {
        return supplierRepository.findCountByTenant(tenant_name);
    }

    public Supplier updateSupplier(Long id, SupplierRequest request) {

        String tenantName = jwtRequestUtils.getTenantName();
        String userId = jwtRequestUtils.getUserId();

        Supplier supplier = supplierRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Supplier not found"));

        // Check if the tenant name matches
        if (!supplier.getTenant().equals(tenantName)) {
            createLogger.createLogger("error", path, "PUT", "Unauthorized to update this supplier; tenant mismatch",
                    "");
            throw new RuntimeException("Unauthorized to update this supplier; tenant mismatch");
        }

        supplier.setSupplier_id(request.getSupplier_id());
        supplier.setSupplier_name(request.getSupplier_name());
        supplier.setContact_person(request.getContact_person());
        supplier.setPhone_number(request.getPhone_number());
        supplier.setEmail_address(request.getEmail_address());
        supplier.setAddress(request.getAddress());
        supplier.setCity(request.getCity());
        supplier.setState_province(request.getState_province());
        supplier.setZip_postal_code(request.getZip_postal_code());
        supplier.setCountry(request.getCountry());
        supplier.setWebsite(request.getWebsite());
        supplier.setSupplier_type(request.getSupplier_type());
        supplier.setNotes(request.getNotes());
        supplier.setCreated_by(userId);
        supplier.setTenant(tenantName);

        // Save the updated supplier
        return supplierRepository.save(supplier);
    }

    public void deleteSupplier(Long id) {

        String tenantName = jwtRequestUtils.getTenantName();

        // Check if the supplier exists
        Supplier supplier = supplierRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("Supplier not found"));

        // Check if the tenantName matches the tenant field in the supplier
        if (!supplier.getTenant().equals(tenantName)) {
            createLogger.createLogger("error", path, "DELETE", "Unauthorized to delete this supplier; tenant mismatch",
                    "");
            throw new IllegalArgumentException("Unauthorized to delete this supplier; tenant mismatch");
        }

        // Delete the supplier
        supplierRepository.deleteById(id);
    }

    public boolean existsByPurchases(Long supplierId) {
        return purchaseRepository.existsBySupplierId(supplierId);
    }

    public boolean existsByGrns(Long supplierId) {
        return grnRepository.existsBySupplierId(supplierId);
    }

}