<?php

namespace App\Services\Reports\CycleCount;

use App\Models\Asset;
use App\Models\AssetType;
use App\Models\AssetStatus;
use App\Models\CycleCountScannedData;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;

/**
 * Service Class for CycleCount Scanning
 *
 */
class CycleCountScanService
{

    public $excludedAssetTypes;

    public $excludedAssetStatuses;

    public function __construct()
    {
        $this->excludedAssetTypes = config('cycle-count.excluded-asset-types');
        $this->excludedAssetStatuses = config('cycle-count.excluded_asset_statuses');
    }

    /**
     * Get array of selected asset types
     * @return array
     */
    public function getSelectedAssetTypes()
    {
        $assetTypeIds = request('asset_type_id');
        if (!is_array($assetTypeIds)) {
            return [$assetTypeIds];
        }

        return $assetTypeIds;
    }

    /**
     * Gets the request asset details
     * @param mixed $assetTag
     * @param mixed $assetTypeId
     * 
     * @return [type]
     */
    public function getReqAssetDetails($assetTag, $assetTypeId)
    {

        $reqAsset = Asset::where(function ($query) use ($assetTag) {
            $query->where('serial_no', $assetTag);
            $query->orWhere('asset_tag', $assetTag);
        })->first();
        // If asset type selected as "All", then don't checked asset type id
        if (!in_array('All', $assetTypeId) && $reqAsset) {

            $reqAsset = Asset::with('assetType')
                ->where(function ($query) use ($assetTag) {
                    $query->where('serial_no', $assetTag);
                    $query->orWhere('asset_tag', $assetTag);
                })
                ->whereIn('asset_type_id', $assetTypeId)->first();

            if (!$reqAsset) {
                return 'type_mismatch';
            }
        }

        return $reqAsset;
    }

    /**
     * Create Variance Scanned Data
     * @param mixed $assetTypeId
     * @param mixed $assetTag
     * 
     * @return [type]
     */
    public function createVarianceScannedData($assetTypeId, $assetTag)
    {
        $excudedAssetTypesIdArray = Cache::remember('excluded-asset-types', 720, function () {
            return AssetType::whereIn('slug', $this->excludedAssetTypes)->pluck('id')->toArray();
        });

        $excludedAssetStatusesIdArray = Cache::remember('excluded-asset-statuses', 720, function () {
            return AssetStatus::whereIn('slug', $this->excludedAssetStatuses)->pluck('id')->toArray();
        });

        $excludedAssetFlag = Asset::where(function ($query) use ($assetTag) {
            $query->where('serial_no', $assetTag);
            $query->orWhere('asset_tag', $assetTag);
        })->where(function ($query) use ($excudedAssetTypesIdArray, $excludedAssetStatusesIdArray) {
            $query->whereIn('asset_type_id', $excudedAssetTypesIdArray)
                ->orWhereIn('asset_status_id', $excludedAssetStatusesIdArray);
        })->count();

        if ($excludedAssetFlag > 0) {
            return false;
        }

        return CycleCountScannedData::create([
            'user_id' => Auth::id(),
            'location_id' => request('location_id'),
            'serial_no' => request('serial_no'),
            'asset_type_ids' => implode(',', $assetTypeId),
        ]);
    }

    /**
     * Get ids of all asset types used in scans.
     * 
     * @param mixed $mergedData
     * 
     * @return array $assetTypeIds
     */
    public function getScannedAssetTypesIds($mergedData)
    {
        $assetTypeIds = [];

        //getting unique asset_type_ids
        $scannedAssetTypes = array_unique($mergedData->pluck('asset_type_ids')->toArray());

        foreach ($scannedAssetTypes as $sannedItem) {
            $assetTypeIds = array_unique(array_merge($assetTypeIds, explode(',', $sannedItem)));
        }

        return $assetTypeIds;
    }

    /**
     * The function checks if an asset exists in a scanned list based on its serialNo.
     * 
     * @param serialNo
     * 
     * @return either the string 'serial_exist' if the check is true, or false if the check is false.
     */
    public function checkExistInScannedList($serialNo)
    {
        $asset = Asset::where('serial_no', $serialNo)->orWhere('asset_tag', $serialNo)->first();

        if ($asset) {
            $check =  CycleCountScannedData::where(function ($query) use ($asset) {
                $query->where('serial_no', $asset->serial_no);
                $query->orWhere('serial_no', $asset->asset_tag);
            })->where([
                'location_id' => request('location_id') ?? '',
            ])
                ->first();
        } else {
            $check =  CycleCountScannedData::where([
                'location_id' => request('location_id') ?? '',
                'serial_no'   => $serialNo ?? '',
            ])
                ->first();
        }
        if ($check) {
            return 'serial_exist';
        }
        return false;
    }
}
