package com.nebula.erp.sales.service;

import com.nebula.erp.sales.model.*;
import com.nebula.erp.sales.repository.CreditRepository;
import com.nebula.erp.sales.repository.SalesRepository;
import com.nebula.erp.sales.repository.SalesReturnRepository;
import com.nebula.erp.sales.requestmodel.CreditRequest;
import com.nebula.erp.sales.requestmodel.SalesReturnRequest;
import com.nebula.erp.sales.utility.CreateLogger;
import com.nebula.erp.sales.utility.JwtRequestUtils;
import jakarta.persistence.EntityNotFoundException;
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.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Service
public class CreditService {

    @Autowired
    private CreditRepository creditRepository;

    @Autowired
    private SalesReturnRepository salesReturnRepository;

    @Autowired
    private SalesRepository salesRepository;

    @Autowired
    private JwtRequestUtils jwtRequestUtils;

    @Autowired
    private CreateLogger createLogger;

    private static final String path = "/credit-notes";

    public Page<CreditNote> getAllCreditNotes(int page, int size, String sales_return_id) {
        String tenantName = jwtRequestUtils.getTenantName();

        Pageable pageable = PageRequest.of(page - 1, size);

        // Use a specification or dynamic query to apply filters
        Specification<CreditNote> spec = Specification.where(null);

        // Filter by tenant name
        spec = spec.and((root, query, criteriaBuilder) ->
                criteriaBuilder.equal(root.get("tenant"), tenantName));

        // Filter by patient ID if provided
        if (sales_return_id != null) {
            spec = spec.and((root, query, criteriaBuilder) ->
                    criteriaBuilder.equal(root.get("sales_return_id"), sales_return_id));
        }

        return creditRepository.findAll(spec, pageable);
    }

    public CreditNote createCredit(CreditRequest creditRequest){
        // Extract Authorization headers from the request
        String tenantName = jwtRequestUtils.getTenantName();
        String userId = jwtRequestUtils.getUserId();

        // Check sale id is exist in the system
        salesRepository.findByIdAndTenant(creditRequest.getSales_id(), tenantName)
                .orElseThrow(() -> new ResourceNotFoundException("Sales not found with id: " + creditRequest.getSales_id()));

        // Check if a SalesReturn record exists with the given sale ID and tenant
        SalesReturn existingSalesReturn = salesReturnRepository.findByIdAndTenant(creditRequest.getSales_return_id(), tenantName)
                .orElseThrow(() -> new ResourceNotFoundException("Sales return not found with id: " + creditRequest.getSales_return_id()));

        double creditLimit = existingSalesReturn.getTotal_amount();

        // Check if the invoice_number already exists
        List<CreditNote> existingCreditNotes = creditRepository.findBySaleReturn(creditRequest.getSales_return_id(), tenantName);

        double usedCredit = existingCreditNotes.stream()
                .mapToDouble(CreditNote::getRefund_amount)
                .sum();

        if((usedCredit + creditRequest.getRefund_amount()) > creditLimit){
            createLogger.createLogger("error", path, "POST", "Credit amount is already refunded. Not able to create credit note!", "");
            throw new IllegalArgumentException("Credit amount is already refunded. Not able to create credit note!");
        }

        // Prepare sales return object
        CreditNote creditNote = new CreditNote();
        creditNote.setCredit_note_id(creditRequest.getCredit_note_id());
        creditNote.setInvoice_id(creditRequest.getInvoice_id());
        creditNote.setDate(creditRequest.getDate());
        creditNote.setSales_id(creditRequest.getSales_id());
        creditNote.setSales_return_id(creditRequest.getSales_return_id());
        creditNote.setCredit_amount(creditLimit);
        creditNote.setRefund_amount(creditRequest.getRefund_amount());
        creditNote.setDiscount_amount(creditRequest.getDiscount_amount());
        creditNote.setPayment_method(creditRequest.getPayment_method());
        creditNote.setReason(creditRequest.getReason());
        creditNote.setCreated_by(userId);
        creditNote.setTenant(tenantName);

        return creditRepository.save(creditNote);
    }

    public Optional<CreditNote> getCredit(Long id){
        String tenantName = jwtRequestUtils.getTenantName();
        return creditRepository.findByIdAndTenant(id, tenantName);
    }

}