package com.utopiaindustries.service;

import com.utopiaindustries.dao.ctp.*;
import com.utopiaindustries.model.ctp.Bundle;
import com.utopiaindustries.model.ctp.FinishedItem;
import com.utopiaindustries.model.ctp.MasterBundle;
import com.utopiaindustries.model.ctp.StitchingOfflineItem;
import com.utopiaindustries.querybuilder.ctp.BundleQueryBuilder;
import com.utopiaindustries.querybuilder.ctp.FinishedItemQueryBuilder;
import com.utopiaindustries.querybuilder.ctp.MasterBundleQueryBuilder;
import com.utopiaindustries.querybuilder.ctp.StichedOfflineItemQueryBuilder;
import com.utopiaindustries.util.NumberUtils;
import com.utopiaindustries.util.StringUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class BundleService {

    private final BundleDAO bundleDAO;
    private  final MasterBundleDAO masterBundleDAO;
    private final CryptographyService cryptographyService;
    private final FinishedItemDAO finishedItemDAO;
    private final StitchingOfflineItemDAO stitchingOfflineItemDAO;
    private final InventoryService inventoryService;
    private final InventoryTransactionLegDAO inventoryTransactionLegDAO;

    public BundleService(BundleDAO bundleDAO, MasterBundleDAO masterBundleDAO, CryptographyService cryptographyService, FinishedItemDAO finishedItemDAO, StitchingOfflineItemDAO stitchingOfflineItemDAO, InventoryService inventoryService, InventoryTransactionLegDAO inventoryTransactionLegDAO) {
        this.bundleDAO = bundleDAO;
        this.masterBundleDAO = masterBundleDAO;
        this.cryptographyService = cryptographyService;
        this.finishedItemDAO = finishedItemDAO;
        this.stitchingOfflineItemDAO = stitchingOfflineItemDAO;
        this.inventoryService = inventoryService;
        this.inventoryTransactionLegDAO = inventoryTransactionLegDAO;
    }

    /*
    * find bundles by params
    * */
    public List<Bundle> getBundles( String id, String sku, String jobCardId, String masterId,String type, String status, String startDate, String endDate, Long count ){
        List<Bundle> bundles = new ArrayList<>();
        if( count == null ){
            count = 100L;
        }
        if( StringUtils.isAnyNotNullOrEmpty( id, sku, jobCardId, masterId, type, status, startDate, endDate ) ){
            String query = BundleQueryBuilder.buildQuery( id, sku, jobCardId, masterId, type, status, startDate, endDate , count );
            System.out.println( query );
            bundles =  bundleDAO.findByQuery( query );
        } else {
            bundles = bundleDAO.findByLimit( count );
        }
        return bundles;
    }

    /*
     * find bundle by id
     * */
    public Bundle getBundlesById( long id){
        return  bundleDAO.find(id);
    }

    /*
    * find bundle by barcode
    * */
    public List<Bundle> getBundles( String barcode){
        List<Bundle> bundles = new ArrayList<>();
        List<Bundle> fetchBundle = bundleDAO.findByBarcodeLike( barcode );
        List<Long> ids =  fetchBundle.stream()
                .map(Bundle::getMasterBundleId)
                .distinct()
                .collect(Collectors.toList());
        if(!ids.isEmpty()){
            List<Long> masterBundles = masterBundleDAO.findByIdAndReceiveIsTrue(ids);
            bundles = fetchBundle.stream()
                    .filter(e -> masterBundles.contains(e.getMasterBundleId())
                            && e.getWrapQuantity().compareTo(
                            e.getProduction() != null ? e.getProduction() : BigDecimal.ZERO) != 0)
                    .collect(Collectors.toList());
        }

        return bundles;
    }

    /*
    *  find master bundles by params
    * */
    public List<MasterBundle> getMasterBundles( String id, String sku, String status, String jobCardId, String startDate, String endDate, Long count ){
        List<MasterBundle> bundles;
        if( count == null ){
            count = 100L;
        }
        if( StringUtils.isAnyNotNullOrEmpty(id, jobCardId, startDate, endDate, sku, status) ){
            String query = MasterBundleQueryBuilder.buildQuery( id, sku, status, jobCardId, startDate, endDate , count );
            System.out.println( query );
            bundles = masterBundleDAO.findByQuery( query );
        } else {
            bundles = masterBundleDAO.findByLimit( count );
        }
        return bundles;
    }

    /*
    * find finished Items by params
    * */
    public List<FinishedItem> getFinishedItem(String id, String itemId, String sku, String createdStartDate, String createdEndDate, String jobCardId, String status ,Long count ){
        List<FinishedItem> finishedItems = new ArrayList<>();
        if( count == null ){
            count = 100L;
        }
        if( StringUtils.isAnyNotNullOrEmpty(id, itemId, sku, createdStartDate, createdEndDate, jobCardId, status ) ){
            String query = FinishedItemQueryBuilder.buildQuery( id, itemId, sku, createdStartDate, createdEndDate, jobCardId, status, count );
            System.out.println( query );
            finishedItems = finishedItemDAO.findByQuery( query );
        } else {
            finishedItems = finishedItemDAO.findByLimit( count );
        }
        return finishedItems;
    }


    /*
     * find finished Items by params
     * */
    public List<StitchingOfflineItem> getStitchedOfflineItems(String id, String itemId, String sku,String status, String createdStartDate, String createdEndDate, Long bundleId, Long count ){
        List<StitchingOfflineItem> stitchingOfflineItems = new ArrayList<>();
        if( count == null ){
            count = 100L;
        }
        if( StringUtils.isAnyNotNullOrEmpty(id, itemId, sku, createdStartDate, createdEndDate, String.valueOf(bundleId) ) ){
            String query = StichedOfflineItemQueryBuilder.buildQuery( id, itemId, sku, status,createdStartDate, createdEndDate, bundleId , count );
            System.out.println( query );
            stitchingOfflineItems = stitchingOfflineItemDAO.findByQuery( query );
        } else {
            stitchingOfflineItems = stitchingOfflineItemDAO.findByLimit( count );
        }
        return stitchingOfflineItems;
    }

    /*
    *
    * */
    public List<Bundle> getBundleByIdAndItemIdAndSku( String term ){
        return bundleDAO.findByTerm( term );
    }

    /**
     * */
    public List<MasterBundle> getMasterBundleByIdTerm( String term, boolean isReceived ){ return masterBundleDAO.findByTermAndNotReceived( term , isReceived);}

    /*
    * create master bundle and tag to child bundles
    * */
    public long createMasterBundle( BundleWrapper wrapper ){
        if( wrapper != null && wrapper.getBundles() != null && ! wrapper.getBundles().isEmpty() ){
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            long itemId = 0;
            String sku = "";
            long jobCardId = 0;
            MasterBundle masterBundle = new MasterBundle();
            masterBundle.setCreatedBy(  authentication.getName() );
            masterBundle.setCreatedAt( LocalDateTime.now() );
            long id = masterBundleDAO.save( masterBundle );
            masterBundle.setId( id );
            masterBundle.setBarcode( cryptographyService.generateRandomString( 15 ) );
            List<Bundle> newBundles = new ArrayList<>();
            for( Bundle bundle : wrapper.getBundles() ){
                bundle.setMasterBundleId( id  );
                bundle.setCurrentProduction(bundle.getWrapQuantity());
                newBundles.add( bundle );
                // sku and item in master bundle
                if( StringUtils.isNullOrEmpty( sku ) ){
                    sku = bundle.getSku();
                }
                if( NumberUtils.isNullOrZero( itemId ) ) {
                    itemId = bundle.getItemId();
                }
                if( NumberUtils.isNullOrZero( jobCardId ) ){
                    jobCardId = bundle.getJobCardId();
                }
            }
            masterBundle.setItemId( itemId );
            masterBundle.setSku( sku );
            masterBundle.setJobCardId( jobCardId );
            // save master
            masterBundleDAO.save( masterBundle );
            //save child bundles
            bundleDAO.saveAll( newBundles );

            inventoryService.createStitchingOfflineItemsFromBundle(newBundles);
            return id;
        }
        return 0;
    }

    /*
    *  find by master id
    * */
    public List<Bundle> findBundlesByMasterId( long masterId ){
        return bundleDAO.findByMasterId( masterId );
    }

}
