<?php

namespace App\Services\Reports\CycleCount;

use App\Models\AssetType;
use App\Models\ReportHistoryVarience;

/**
 * Service Class for CycleCountReportService Report
 *
 * Assets Difference between the physical location and Database location
 */
class CycleCountHistoryService
{
    public $excludedAssetTypes;

    public $excludedAssetStatuses;

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

    /**
     * Generate Variance History page content
     *
     * @param request
     */
    public function data()
    {
        $histories = new ReportHistoryVarience;
        $histories = $this->filter($histories);
        $historyDataForList = $histories;
        $historyDataForGraph = $histories;
        $highest = $histories->orderBy('accuracy', 'DESC')->first();

        // Here applying orderBy on $histories for lowest still gives higest value so rewrite it again
        $historiesForLowest = new ReportHistoryVarience;
        $historiesForLowest = $this->filter($historiesForLowest);
        $lowest = $historiesForLowest->orderBy('accuracy', 'ASC')->first();


        // Sorting
        $column = request()->input('order.0.column');
        $dir = request()->input('order.0.dir');
        $sortableColumns = ['id', 'location_name', 'date', 'id', 'accuracy'];
        $sortColumn = $sortableColumns[$column] ?? 'id';

        $sortDirection = $dir ?? 'asc';
        $historyDataForList = $histories->orderBy($sortColumn, $sortDirection);

        $average = $historyDataForList->avg('accuracy');
        $average = $average ? round($average, 2) : 0;

        $heighestAccuracy =  ($highest && $highest->accuracy) ? $highest->accuracy : 0;
        $heighestDate = ($highest && $highest->date) ? date('M, Y', strtotime($highest->date)) : '';


        $lowestAccuracy = ($lowest && $lowest->accuracy) ? $lowest->accuracy : 0;
        $lowestDate = ($lowest && $lowest->date) ? date('M, Y', strtotime($lowest->date)) : '';

        $count = $historyDataForList->count();
        $histories = $this->getOutputData($historyDataForList);

        $graphData = [];

        foreach ($historyDataForGraph->get() as $history) {
            $graphData[] = [
                'date' => date('d M y', strtotime($history->date)),
                'accuracy' => $history->accuracy,
            ];
        }

        return compact(
            'histories',
            'count',
            'average',
            'heighestAccuracy',
            'heighestDate',
            'lowestAccuracy',
            'lowestDate',
            'graphData'
        );
    }


    /**
     * get history data for listing page
     */
    public function filter($histories = null)
    {
        $searchValues = request('form');
        $columnsForExactMatch = ['location_id'];
        $columnsForDateRangeMatch = ['date_from', 'date_to'];

        foreach ($searchValues as $filterKey => $filterValue) {

            if (!empty($filterValue)) {

                if (in_array($filterKey, $columnsForExactMatch)) {
                    $histories = $histories->filterByExactMatch($filterKey, $filterValue);
                }
                if (in_array($filterKey, $columnsForDateRangeMatch)) {
                    $histories = $histories->filterByDateRangeMatch($filterKey, $filterValue);
                }
            }
        }


        return $histories;
    }

    /**
     * Adding Limit to the query (Datatable pagination) and take the result
     *
     * @param object $histories    App\Models\ReportHistoryVarience;
     */
    public function getOutputData($histories)
    {
        $start = request('start');
        $limit = request('length');

        if ($limit != -1) {
            $histories = $histories->offset($start)
                ->limit($limit);
        }
        return $histories->orderBy('created_at', 'desc')->get();
    }

    /**
     * After Fetching the data from Db, making the output for Data table
     *
     * @param object $histories    App\Models\ReportHistoryVarience;
     * @param integer $start       pagination starting index
     *
     */
    public function getReportData($histories, $start)
    {
        $parentIndex = $start;
        $data = [];

        foreach ($histories as $key => $history) {
            $parentIndex++;

            $nestedData = $this->getNestedData($history, $parentIndex);
            $data[] = $nestedData;
        }

        return $data;
    }

    /**
     * Generating an array for data table fields
     *
     * @param object $history   App\Models\ReportHistoryVarience;
     * @param integer $index    Serial number
     *
     * @return array()
     */
    public function getNestedData($history, $index)
    {
        $historyDetailslink = route('cycle-count.history.details', $history->id);
        $nestedData['id'] = $index;
        $nestedData['room_name'] = "<a href=$historyDetailslink>$history->location_name</a>";
        $nestedData['date'] = $history->date;

        $assetTypes = "";
        if ($history->asset_type_ids) {
            $assetTypes = $this->getSelectedAssetTypes($history->asset_type_ids);
        }

        $nestedData['asset_types'] = $assetTypes;
        $nestedData['accuracy'] = $history->accuracy . '%';
        return $nestedData;
    }


    /**
     * Function to get selected asset types
     * @param mixed $asset_type_ids
     * 
     * @return [type]
     */
    public function getSelectedAssetTypes($asset_type_ids)
    {
        $assetTypeIds = explode(',', $asset_type_ids);
        if (in_array("All", $assetTypeIds)) {
            return "All Asset Types";
        }

        return implode(', ', AssetType::whereIn('id', $assetTypeIds)->pluck('name')->toArray());
    }

    /**
     * Store the variance report to db
     * @param mixed $datasNotScanned
     * @param mixed $assetsMatched
     * @param mixed $assetsNotMatched
     * @param mixed $assetsNotInDatabase
     * @param mixed $count
     * @param mixed $accuracy
     * @param mixed $userName
     * @param mixed $createdDate
     * @param mixed $userId
     * @param mixed $reportName
     * @param mixed $totalScanned
     * @param mixed $locationId
     * @param mixed $locationName
     * @param mixed $reportCsvFile
     * @param mixed $assetTypeIdString
     * @param mixed $variance
     * @param mixed $positiveVariance
     * 
     * @return [type]
     */
    public function saveVarienceReport($datasNotScanned, $assetsMatched, $assetsNotMatched, $assetsNotInDatabase, $count, $accuracy, $userName, $createdDate, $userId, $reportName, $totalScanned, $locationId, $locationName, $reportCsvFile, $assetTypeIdString, $variance, $positiveVariance)
    {

        return ReportHistoryVarience::firstorCreate([
            'date' => convert_to_db_date($createdDate),
            'user_id' => $userId,
            'name' => $reportName,
            'scanned_by' => $userName,
            'match_n' => $assetsNotMatched,
            'match_y' => $assetsMatched,
            'total_assets' => $count,
            'total_assets_scanned' => $totalScanned,
            'assets_not_in_db' => $assetsNotInDatabase,
            'assets_not_scanned' => count($datasNotScanned),
            'location_id' => $locationId,
            'asset_type_ids' => $assetTypeIdString,
            'location_name' => $locationName,
            'variance' => $variance,
            'accuracy' => $accuracy,
            'positive_variance' => $positiveVariance,
            'report_csv' => $reportCsvFile
        ])->id;
    }
}
