import grails.orm.PagedResultList

/**
* Service class that encapsulates the business logic for InventoryItem searches.
*/
class InventoryItemSearchService {

    boolean transactional = false

    def dateUtilService
    def messageSource

    def paramsMax = 100000

    /**
    * Selects and returns the correct search results based on the supplied quickSearch.
    * @param params The request params, may contain params.quickSearch string to specify the search.
    * @param locale The locale to use when generating result.message.
    */
    def getQuickSearch(params, locale) {
        def result = [:]
        result.quickSearch = params.quickSearch ?: "all"

        def getMessage = { Map m ->
            messageSource.getMessage(m.code, m.args == null ? null : m.args.toArray(), locale)
        }

        switch (result.quickSearch) {
            case "inventoryBelowReorder":
                result.inventoryItemList = getInventoryBelowReorder(params)
                if(result.inventoryItemList.totalCount > 0)
                    result.message = getMessage(code:"inventoryItem.search.text.below.reorder.description")
                else
                    result.message = getMessage(code:"inventoryItem.search.text.below.reorder.none.found")
                break
            case "inventoryBelowReorderAll":
                result.inventoryItemList = getInventoryBelowReorder(params, false)
                if(result.inventoryItemList.totalCount > 0)
                    result.message = getMessage(code:"inventoryItem.search.text.below.reorder.all.description")
                else
                    result.message = getMessage(code:"inventoryItem.search.text.below.reorder.none.found")
                break
            case "recentlyUsed":
                result.daysBack = params.daysBack?.isInteger() ? params.daysBack.toInteger() : 14
                result.inventoryItemList = getRecentlyUsed(params, result.daysBack)
                if(result.inventoryItemList.totalCount > 0)
                    result.message = getMessage(code:"inventoryItem.search.text.recently.used.description", args:[result.daysBack])
                else
                    result.message = getMessage(code:"inventoryItem.search.text.recently.used.none.found", args:[result.daysBack])
                break
            default:
                result.inventoryItemList = getAll(params)
                if(result.inventoryItemList.totalCount > 0)
                    result.message = getMessage(code:"inventoryItem.search.text.all.description")
                else
                    result.message = getMessage(code:"inventoryItem.search.text.all.none.found")
                break
        } // switch.

        // Success.
        return result

    } // getQuickSearch

    /**
    * Get all inventory items.
    * @param params The request params.
    */
    def getAll(params) {
        params.max = Math.min(params?.max?.toInteger() ?: 10, paramsMax)
        params.offset = params?.offset?.toInteger() ?: 0
        params.sort = params?.sort ?: "name"
        params.order = params?.order ?: "asc"

        def inventoryItemList = InventoryItem.createCriteria().list(
            max: params.max,
            offset: params.offset,
            sort: params.sort,
            order: params.order) {
            } // createCriteria
    } // getAll

    /**
    * List inventory items that are below reorder point.
    * @param params The request params.
    * @param onlyReorderEnabled Only include items with reorder enabled, defaults to true.
    */
    def getInventoryBelowReorder(params, onlyReorderEnabled=true) {
        params.max = Math.min(params?.max?.toInteger() ?: 10, paramsMax)
        params.offset = params?.offset?.toInteger() ?: 0
        params.sort = params?.sort ?: "name"
        params.order = params?.order ?: "asc"

        def inventoryItemList = InventoryItem.createCriteria().list(
            max: params.max,
            offset: params.offset,
            sort: params.sort,
            order: params.order) {
                eq("isActive", true)
                if(onlyReorderEnabled)
                    eq("enableReorder", true)
                leProperty("unitsInStock", "reorderPoint")
            } // createCriteria
    } // getInventoryBelowReorder

    /**
    * Get a list of recently used inventory items.
    * @param params The request params.
    * @param daysBack The number of days back to get results for.
    */
    def getRecentlyUsed(params, daysBack) {
        def paginateParams = [:]
        paginateParams.max = Math.min(params?.max?.toInteger() ?: 10, paramsMax)
        paginateParams.offset = params?.offset?.toInteger() ?: 0

        def sort = "inventoryItem." + (params?.sort ?: "name")
        def order = params?.order == "desc" ? "desc" : "asc"
        def orderBy = " order by " + sort + ' ' + order

        def namedParams = [:]
        namedParams.startOfDay = dateUtilService.today - daysBack

        def baseQuery = "from InventoryItem as inventoryItem \
                                        left join inventoryItem.inventoryMovements as inventoryMovement \
                                        where (inventoryItem.isActive = true \
                                                    and inventoryMovement.date > :startOfDay \
                                                    and inventoryMovement.inventoryMovementType = 1 \
                                                    )"

        def searchQuery = "select distinct inventoryItem " + baseQuery + orderBy
        def list = InventoryItem.executeQuery(searchQuery, namedParams, paginateParams)

        def countQuery = "select count(distinct inventoryItem) as inventoryItemCount " + baseQuery
        def totalCount = InventoryItem.executeQuery(countQuery, namedParams)[0].toInteger()

        def inventoryItemInstanceList = new PagedResultList(list, totalCount)
        return inventoryItemInstanceList
    } // getRecentlyUsed

} // end class