<?php

namespace App\Services\Reports\DepreciationValue;

use App\Http\Responses\ReportOutputData;
use App\Repositories\CommonFilterRepository;
use App\Repositories\Reports\DepreciationValueRepository;
use App\Services\Reports\AbstractReportService;

class DepreciationValueDataTableService extends AbstractReportService
{
    protected $repository;
    protected $commonFilterRepository;
    protected $reportOutputData;

    /**
     * Constructs a new instance of the class.
     *
     * @param DepreciationValueRepository $repository The repository instance.
     * @param CommonFilterRepository $commonFilterRepository The common filter repository instance.
     * @param ReportOutputData $reportOutputData The report output data instance.
     */
    public function __construct(DepreciationValueRepository $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()
    {
        $requestedData = request()->form;
        $inputData = $this->getInputData($requestedData);
        $assets = $this->repository->getData();
        $assets = $this->filterWithInputData($assets, $inputData);
        $count  = $assets->count();
        $assets = $this->reportOutputData->getOutputData($assets, ['id' => 'desc']);

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

    /**
     * Filter the query results based on the filters applied
     *
     * @return object
     */
    public function filterWithInputData($query, array $inputData)
    {
        $query = $this->commonFilterRepository->filterWithDirectFields($query, 'asset_type_id', $inputData['asset_type']);
        $query = $this->commonFilterRepository->filterWithDirectFields($query, 'technical_spec_id', $inputData['technical_spec_id']);
        $query = $this->commonFilterRepository->filterWithDirectFields($query, 'make_and_model_id', $inputData['make_and_model_id']);
        $query = $this->commonFilterRepository->filterWithWhereHasRelationFields($query, 'makeAndModel', 'manufacturer_id', $inputData['manufacturer']);

        return $query;
    }

    /**
     * Taking the filter field data for listing
     */
    public function getInputData(array $requestData): array
    {
        return [
            'asset_type' => $requestData['asset_type'] ?? '',
            'technical_spec_id' => array_filter((array) ($requestData['technical_spec'] ?? [])),
            'make_and_model_id' => array_filter((array) ($requestData['make_and_model'] ?? [])),
            'manufacturer' => array_filter((array) ($requestData['manufacturer'] ?? [])),
        ];
    }

    /**
     * Retrieves the nested data for generating a report.
     *
     * @param mixed $asset The asset object.
     * @return array The nested data for the report.
     */
    public function getReportNestedData($asset): array
    {
        $nestedData = [];
        $nestedData['report']['asset_tag']          = $nestedData['export']['Asset Tag #'] = $asset->asset_tag;
        $nestedData['report']['serial_no']          = $nestedData['export']['Serial #'] = $asset->serial_no;
        $nestedData['report']['hardware_standard']  = $nestedData['export']['Hardware Standard'] = $asset->makeAndModel?->makeModelName;
        $nestedData['report']['technical_spec']     = $nestedData['export']['Technical Specs'] = $asset->technicalSpec?->details;
        $nestedData['report']['asset_status']       = $nestedData['export']['Asset Status'] = $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 : '');
        $nestedData['report']['original_value']     = $nestedData['export']['Original Value'] = $asset?->original_value ? config('currency.currency_symbol') . number_format((float)$asset->original_value) : '';
        $nestedData['report']['depreciated_value']  = $nestedData['export']['Depreciation Value'] = $asset?->depreciated_value ? config('currency.currency_symbol') . number_format((float)$asset->depreciated_value) : '';
        $nestedData['report']['age']                = $nestedData['export']['Asset Age'] = $asset->AssetAge;

        return $nestedData;
    }

    /**
     * Retrieves the nested data for a given item.
     *
     * @param mixed $item The item for which to retrieve the nested data.
     * @param int $index The index of the item.
     * @return array The nested data for the item.
     */
    public function getNestedData($item, $index)
    {
        $commonData = $this->getReportNestedData($item);
        $nestedData = $commonData['report'];
        $nestedData['id'] = $index;
        $nestedData['asset_tag'] = generateAssetLink($item->id, $item->asset_tag);
        $nestedData['serial_no'] = generateAssetLink($item->id, $item->serial_no);
        $nestedData['user_location'] = $item->user ? generateUserLink($item->user?->id, $nestedData['user_location']) : generateLocationLink($item->location?->id, $nestedData['user_location']);;

        return $nestedData;
    }

    /**
     * Retrieves the output data based on the provided assets and data.
     *
     * @param mixed[] $assets The array of assets.
     * @param array $data The array of data.
     * @return mixed[] The modified array of data.
     */
    public function getOutputData($assets, array $data)
    {
        $parentIndex = 0;

        foreach ($assets as $asset) {
            ++$parentIndex;
            $nestedData = $this->getNestedData($asset, $parentIndex);
            $data[] = $nestedData;
        }

        return $data;
    }

    /**
     * Export the data.
     *
     * @return mixed
     */
    public function exportData()
    {
        $requestedData = request()->all();
        $inputData = $this->getInputData($requestedData);
        $assets = $this->repository->getData();
        $assets = $this->filterWithInputData($assets, $inputData);
        $assets = $assets->orderBy('id', 'desc');

        return $assets;
    }
}
