<?php

namespace App\Services\Reports;

use App\Repositories\Reports\LostOrStolenValueRepository;
use App\Repositories\CommonFilterRepository;
use App\Http\Responses\ReportOutputData;
use App\Http\Traits\DepreciationValueTrait;
use Carbon\Carbon;
use DB;

/**
 * Service class for Lost/Stolen Value Report
 */
class LostOrStolenValueService extends AbstractReportService
{
    use DepreciationValueTrait;

    protected $repository;
    protected $commonFilterRepository;
    protected $reportOutputData;

    /**
     * Construct of LostOrStolenValueService
     * @param LostOrStolenValueRepository $repository The repository for the Lost/Stolen Value Repository entity
     * @param CommonFilterRepository $commonFilterRepository The repository for the CommonFilter entity
     * @param ReportOutputData $reportOutputData The ReportOutputData entity
     */
    public function __construct(LostOrStolenValueRepository $repository, CommonFilterRepository $commonFilterRepository, ReportOutputData $reportOutputData)
    {
        $this->repository = $repository;
        $this->commonFilterRepository = $commonFilterRepository;
        $this->reportOutputData = $reportOutputData;
    }

    /**
     * Data to the Report data table
     *
     * @return void
     */
    public function data()
    {
        $result = $this->repository->getLostOrStolenValueAssets();
        $result = $this->filterWithInputData($result);
        $count  = $result->count();
        $result = $this->reportOutputData->getOutputData($result, ['id' => 'asc']);

        return compact('result', 'count');
    }

    /**
     * Filter the query results based on the filters applied
     *
     * @param  mixed $assets
     * @return object
     */
    public function filterWithInputData($assets)
    {
        $requestedData = request()->form ? request()->form : request()->all();
        $assets = $this->commonFilterRepository->filterWithDirectFields($assets, 'assets.asset_type_id', $requestedData['asset_type'] ?? '');
        $assets = $this->commonFilterRepository->filterWithDirectFields($assets, 'assets.make_and_model_id', $requestedData['make_and_model'] ?? '');
        $assets = $this->commonFilterRepository->filterWithDirectFields($assets, 'assets.user_id', $requestedData['user'] ?? '');
        $assets = $this->commonFilterRepository->filterWithDirectFields($assets, 'location_id', $requestedData['location'] ?? '');
        $assets = $this->commonFilterRepository->filterWithWhereHasRelationFields($assets, 'makeAndModel.manufacturer', 'id', $requestedData['manufacturer'] ?? '');
        $assets = $this->commonFilterRepository->filterWithRelationalDateRange($assets, 'latestLostOrStolenAssetHistory', 'created_at', $requestedData['date_from'], $requestedData['date_to']);
        return $assets;
    }

    /**
     * export Data as csv
     *
     * @return mixed
     */
    public function exportData()
    {
        $assets  = $this->repository->getLostOrStolenValueAssets();
        $assets  = $this->filterWithInputData($assets);
        $assets  = $assets->orderBy('id');

        return $assets;
    }


    /**
     * get Report and export common Nested Data
     *
     * @param  mixed $history
     * @return void
     */
    public function getReportNestedData($asset)
    {
        $nestedData['report']['asset_tag'] = $nestedData['export']['Asset Tag #'] = $asset->asset_tag;
        $nestedData['report']['serial_number'] = $nestedData['export']['Serial #'] = $asset->serial_no;
        $nestedData['report']['type'] = $nestedData['export']['Asset Type'] = $asset->assetType ? $asset->assetType->name : '';
        $nestedData['report']['hardware_standard'] = $nestedData['export']['Hardware Standard'] = optional($asset->makeAndModel)->name;
        $nestedData['report']['asset_status'] = $nestedData['export']['Asset Status'] = $asset->assetStatus ? $asset->assetStatus->name : '';
        $nestedData['report']['user_location'] = $nestedData['export']['User/Location'] = $asset->user ? ($asset->user->first_name . ' ' . $asset->user->last_name) : ($asset->location ? $asset->location->room_name : '');

        if ($asset->user && $asset->location) {
            $nestedData['report']['user_location'] = $nestedData['export']['User/Location'] = ($asset->user->first_name . ' ' . $asset->user->last_name . ' / ' . $asset->location->room_name);
        }

        $nestedData['report']['stolen_lost_date'] = $nestedData['export']['Stolen/Lost Date'] = $asset->latestLostOrStolenAssetHistory?->created_date;
        $nestedData['report']['age_when_stolen_lost'] = $nestedData['export']['Age When Lost/Stolen'] = calculateAgeToDate($asset->created_at, $asset->latestLostOrStolenAssetHistory?->created_at);
        $nestedData['report']['original_value'] = $nestedData['export']['Original Value'] = config('currency.currency_symbol') . number_format($asset->originalValue);
        $nestedData['report']['depreciated_value'] = $nestedData['export']['Depreciated Value'] = config('currency.currency_symbol') . number_format($asset->depreciatedValue);
        $nestedData['report']['last_modified_date'] = $nestedData['export']['Last Modified Date'] = $asset->latestAssetHistory ?  $asset->latestAssetHistory->updated_at : '';
        $nestedData['report']['last_modified_by'] = $nestedData['export']['Last Modified By'] = $asset->latestAssetHistory ? optional($asset->latestAssetHistory->user)->user_name : '';

        return $nestedData;
    }

    /**
     * nested data for report
     *
     * @return array
     */
    public function getNestedData($asset, $index)
    {
        $nestedData = [];
        $assetTagLink = route('assets.show', $asset->id);
        $commonData = $this->getReportNestedData($asset);
        $nestedData = $commonData['report'];
        $nestedData['id']   = $index;
        $nestedData['asset_tag'] = generateAssetLink($asset->id, $asset->asset_tag);
        $nestedData['serial_number'] = generateAssetLink($asset->id, $asset->serial_no);

        $userAndLocation = '';
        if ($asset->user) {
            $userAndLocation = generateUserLink($asset->user?->id, $asset->user?->user_name);
        }

        if ($asset->location) {
            $userAndLocation = generateLocationLink($asset->location->id, $asset->location->room_name);
        }

        if ($asset->user && $asset->location) {
            $userAndLocation .= ' / ' . generateLocationLink($asset->location->id, $asset->location->room_name);
        }
        $nestedData['user_location'] = $userAndLocation;
        $nestedData['last_modified_by'] = generateUserLink($asset->latestAssetHistory?->user?->id, $asset->latestAssetHistory?->user?->user_name);

        return $nestedData;
    }


    /**
     * Get widget count data
     *
     * @param  date $dateFrom
     * @param  date $dateTo
     *
     * @return array
     */
    public function getWidgetCountData($dateFrom, $dateTo)
    {
        $assets = $this->repository->getLostOrStolenValueAssets();
        if (request()->ajax()) {
            $assets = $this->filterWithInputData($assets);
        } else {
            $assets = $this->commonFilterRepository->filterWithRelationalDateRange($assets, 'latestLostOrStolenAssetHistory', 'created_at', $dateFrom, $dateTo);
        }

        $count['assets'] = $assets->count();
        $count['asset_depreciation_value'] = config('currency.currency_symbol'). number_format($this->getDepreciationValue($assets));
        return $count;
    }

    /**
     * Retrieves the "from date" from the given request or defaults to 30 days before the current day
     *
     * @return Carbon The date retrieved from the request or the default date.
     */
    public function getFromDate()
    {
        return request()->has('date_from') ? format_date_to_carbon(request('date_from')) : thirty_days_before_current_date();
    }

    /**
     * Retrieves the "to date" from the given request or defaults to the current day
     *
     * @return \Carbon\Carbon The "to date" value.
     */
    public function getToDate()
    {
        return request()->has('date_to') ? format_date_to_carbon(request('date_to')) : Carbon::now()->format(config('date.formats.read_date_format'));
    }
}
