/*
**************************************************************************************
* Program Name  : PurchaseOrderServiceImpl.java
* Author        : Kawade Swapnali
* Date          : Feb 14, 2026
* System Name   : gswbs
* SRF No.       : 
* Purpose       : To implement business logic for Purchase Order module such as
*                 Fetch, Save (bulk with auto PurchaseOrder ID generation),
*                 Update and Delete (single & bulk) with duplicate validation.
*
* Fields        : purchaseOrderId (PK),
*                 purchaseOrderNo,
*                 vendorName,
*                 vendorGSTNo,
*                 vendorAddress,
*                 requestedBy,
*                 purchaseOrderStatus,
*                 assetType,
*                 assetMake,
*                 assetModel,
*                 description,
*                 quantity,
*                 unitPrice,
*                 gstPercentage,
*                 gstAmount,
*                 subTotal,
*                 grandTotal,
*                 purchaseOrderCreateDate,
*                 deliveryLocation,
*                 expectedDate,
*                 loginId,
*                 status
*
* Functions     : getSinglePurchaseOrder(),
*                 getAllPurchaseOrderByLoginId(),
*                 saveAllPurchaseOrder(),
*                 update(),
*                 delete(),
*                 multipalDelete()
*
* Called From   : PurchaseOrderController
* Beans Accessed: PurchaseOrderRepository, PurchaseOrder (Entity)
**************************************************************************************
*/
package com.coder.purchase.order.serviceImpl;

import java.time.LocalDate;
import java.time.Year;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import com.coder.purchase.order.client.AssetMakeServiceClient;
import com.coder.purchase.order.client.AssetTypeServiceClient;
import com.coder.purchase.order.dto.PurchaseOrderDTO;
import com.coder.purchase.order.model.PurchaseOrder;
import com.coder.purchase.order.model.SaveToPurchaseOrderResponse;
import com.coder.purchase.order.repository.PurchaseOrderRepository;
import com.coder.purchase.order.service.PurchaseOrderService;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class PurchaseOrderServiceImpl implements PurchaseOrderService {
	@Autowired
	private AssetTypeServiceClient assetTypeServiceClient;
	
	@Autowired
	private AssetMakeServiceClient assetMakeServiceClient;
    @Autowired
    private final PurchaseOrderRepository purchaseOrderRepository;

    /* FETCH SINGLE PurchaseOrder BY PurchaseOrder ID */
    @Override
    public PurchaseOrderDTO getSinglePurchaseOrder(String purchaseOrderId) {

        return purchaseOrderRepository.findById(purchaseOrderId)
                .map(this::convertPurchaseOrderIntoPurchaseOrderDTO)
                .orElseThrow(() ->
                        new NoSuchElementException("Purchase Order record does not exist!"));
    }
    /* FETCH ALL PURCHASE ORDER */
    @Override
    public List<PurchaseOrderDTO> fetchAllPurchaseOrder() {

        return purchaseOrderRepository.findAll()
                .stream()
                .map(this::convertPurchaseOrderIntoPurchaseOrderDTO)
                .collect(Collectors.toList());
    }

    /*
     * FETCH ALL PURCHASEORDER BY LOGIN ID
     */
    @Override
    public List<PurchaseOrderDTO> getAllPurchaseOrderByCreatedBy(String createdBy) {

        return purchaseOrderRepository.findAllByCreatedBy(createdBy)
                .stream()
                .map(this::convertPurchaseOrderIntoPurchaseOrderDTO)
                .collect(Collectors.toList());
    }

    /*
     * SAVE MULTIPLE PurchaseOrders AT ONE TIME AND AUTO-GENERATE ID
     * Example: PO/2026/001
     */
    @Override
    public SaveToPurchaseOrderResponse saveAllPurchaseOrder(List<PurchaseOrder> purchaseOrders) {

        String prefix = "PO";
        int currentYear = Year.now().getValue();
        String idPrefix = prefix + "/" + currentYear + "/";

        List<PurchaseOrder> saveToPurchaseOrder = new ArrayList<>();
        List<String> duplicateMessages = new ArrayList<>();

        List<String> existingIds =
                purchaseOrderRepository.findTopByPrefix(idPrefix, PageRequest.of(0, 1));

        int nextNumber = 1;
        if (!existingIds.isEmpty()) {
            String latestId = existingIds.get(0);   // PO/2026/001
            String[] parts = latestId.split("/");

            if (parts.length == 3) {
                try {
                    nextNumber = Integer.parseInt(parts[2]) + 1;
                } catch (NumberFormatException e) {
                    nextNumber = 1;
                }
            }
        }

        for (PurchaseOrder d : purchaseOrders) {

            Optional<PurchaseOrder> exists =
                    purchaseOrderRepository.checkDuplicateRecords(d.getPurchaseOrderNumber(), d.getCreatedBy(), d.getCreatedDate());

            if (exists.isPresent()) {
                duplicateMessages.add(
                        "Purchase Order already exists for vendor: " + d.getPurchaseOrderNumber());
                continue;
            }

            String formattedNumber = String.format("%03d", nextNumber++);
            d.setPurchaseOrderId(idPrefix + formattedNumber);
            saveToPurchaseOrder.add(d);
        }

        List<PurchaseOrder> saved = purchaseOrderRepository.saveAll(saveToPurchaseOrder);

        SaveToPurchaseOrderResponse response = new SaveToPurchaseOrderResponse();
        response.setSavedPurchaseOrders(saved); 
        response.setDuplicateMessages(duplicateMessages);
        return response;
    }

    /*
     * UPDATE SINGLE PurchaseOrder BY PurchaseOrder ID
     */
    @Override
    public PurchaseOrder update(String purchaseOrderId, PurchaseOrder purchaseOrder) {

        Optional<PurchaseOrder> purchaseOrderOp =
                purchaseOrderRepository.findById(purchaseOrderId);

        if (purchaseOrderOp.isEmpty()) {
            throw new NoSuchElementException("Purchase Order record does not exist!");
        }

        PurchaseOrder db = purchaseOrderOp.get();

        /* ========= PO BASIC INFO ========= */

        db.setPurchaseOrderNumber(purchaseOrder.getPurchaseOrderNumber());
        db.setPurchaseOrderDate(purchaseOrder.getPurchaseOrderDate());
        db.setExpectedDeliveryDate(purchaseOrder.getExpectedDeliveryDate());
        db.setVendorId(purchaseOrder.getVendorId());
        db.setVendorName(purchaseOrder.getVendorName());
        db.setVendorContact(purchaseOrder.getVendorContact());
        db.setVendorGSTNo(purchaseOrder.getVendorGSTNo());
        db.setShippingAddress(purchaseOrder.getShippingAddress());
        db.setAssetType(purchaseOrder.getAssetType());
        db.setAssetMake(purchaseOrder.getAssetMake());
        db.setAssetModel(purchaseOrder.getAssetModel());
        db.setQuantity(purchaseOrder.getQuantity());
        db.setUnitPrice(purchaseOrder.getUnitPrice());
        db.setDiscount(purchaseOrder.getDiscount());
        db.setGst(purchaseOrder.getGst());
        db.setSubTotal(purchaseOrder.getSubTotal());
        db.setTotalTax(purchaseOrder.getTotalTax());
        db.setTotalDiscount(purchaseOrder.getTotalDiscount());
        db.setGrandTotal(purchaseOrder.getGrandTotal());
        db.setAdvancePaid(purchaseOrder.getAdvancePaid());
        db.setBalanceAmount(purchaseOrder.getBalanceAmount());
        db.setPaymentStatus(purchaseOrder.getPaymentStatus());
        db.setPaymentMode(purchaseOrder.getPaymentMode());
        db.setTransactionReference(purchaseOrder.getTransactionReference());
        db.setPaymentDueDate(purchaseOrder.getPaymentDueDate());
        db.setApprovedBy(purchaseOrder.getApprovedBy());
        db.setApprovedDate(purchaseOrder.getApprovedDate());
        db.setRemarks(purchaseOrder.getRemarks());
        db.setPoStatus(purchaseOrder.getPoStatus());
        db.setCreatedBy(purchaseOrder.getCreatedBy());
        db.setCreatedDate(purchaseOrder.getCreatedDate());
        db.setUpdatedDate(purchaseOrder.getUpdatedDate());
        db.setStatus(purchaseOrder.getStatus());
        
        return purchaseOrderRepository.saveAndFlush(db);
    }

    /* DELETE MULTIPLE PurchaseOrders AT ONE TIME BY PurchaseOrder ID LIST */
    @Override
    public boolean multipalDelete(List<String> purchaseOrderIds) {
        purchaseOrderRepository.deleteAllById(purchaseOrderIds);
        return true;
    }
    @Override
    public PurchaseOrderDTO convertPurchaseOrderIntoPurchaseOrderDTO(PurchaseOrder purchaseOrder) {

        PurchaseOrderDTO dto = new PurchaseOrderDTO();

        /* ================= BASIC ================= */
        dto.setPurchaseOrderId(purchaseOrder.getPurchaseOrderId());
        dto.setPurchaseOrderNumber(purchaseOrder.getPurchaseOrderNumber());
        dto.setPurchaseOrderDate(purchaseOrder.getPurchaseOrderDate());
        dto.setExpectedDeliveryDate(purchaseOrder.getExpectedDeliveryDate());

        dto.setVendorId(purchaseOrder.getVendorId());
        dto.setVendorName(purchaseOrder.getVendorName());
        dto.setVendorContact(purchaseOrder.getVendorContact());
        dto.setVendorGSTNo(purchaseOrder.getVendorGSTNo());
        dto.setShippingAddress(purchaseOrder.getShippingAddress());

        /* ================= ASSET ================= */
        dto.setAssetType(purchaseOrder.getAssetType());
        dto.setAssetMake(purchaseOrder.getAssetMake());
        dto.setAssetModel(purchaseOrder.getAssetModel());

        /* ================= PRICING ================= */
        dto.setQuantity(purchaseOrder.getQuantity());
        dto.setUnitPrice(purchaseOrder.getUnitPrice());
        dto.setDiscount(purchaseOrder.getDiscount());
        dto.setGst(purchaseOrder.getGst());

        dto.setSubTotal(purchaseOrder.getSubTotal());
        dto.setTotalTax(purchaseOrder.getTotalTax());
        dto.setTotalDiscount(purchaseOrder.getTotalDiscount());
        dto.setGrandTotal(purchaseOrder.getGrandTotal());
        dto.setAdvancePaid(purchaseOrder.getAdvancePaid());
        dto.setBalanceAmount(purchaseOrder.getBalanceAmount());

        /* ================= PAYMENT ================= */
        dto.setPaymentStatus(purchaseOrder.getPaymentStatus());
        dto.setPaymentMode(purchaseOrder.getPaymentMode());
        dto.setTransactionReference(purchaseOrder.getTransactionReference());
        dto.setPaymentDueDate(purchaseOrder.getPaymentDueDate());

        /* ================= APPROVAL ================= */
        dto.setApprovedBy(purchaseOrder.getApprovedBy());
        dto.setApprovedDate(purchaseOrder.getApprovedDate());
        dto.setRemarks(purchaseOrder.getRemarks());
        dto.setPoStatus(purchaseOrder.getPoStatus());

        /* ================= AUDIT ================= */
        dto.setCreatedBy(purchaseOrder.getCreatedBy());
        dto.setCreatedDate(purchaseOrder.getCreatedDate());
        dto.setUpdatedDate(purchaseOrder.getUpdatedDate());
        dto.setStatus(purchaseOrder.getStatus());

        return dto;
    }
//    @Override
//    public PurchaseOrder getById(String purchaseOrderId) {
//
//        return purchaseOrderRepository.findById(purchaseOrderId)
//                .orElseThrow(
//                    () -> new RuntimeException("Purchase Order Not Found"));
//    }
//
//    @Override
//    public PurchaseOrder save(PurchaseOrder po) {
//
//        return purchaseOrderRepository.save(po);
//    }
}
