<?php

namespace App\Services\Terminations\HrCollection;

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

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

    /**
     * Constructor for the class.
     *
     * @param TermsCollectionReportRepository $repository The TermAssets repository.
     * @param CommonFilterRepository $commonFilterRepository The CommonFilterRepository.
     * @param ReportOutputData $reportOutputData The ReportOutputData.
     */
    public function __construct(TermsCollectionReportRepository $repository, CommonFilterRepository $commonFilterRepository, ReportOutputData $reportOutputData)
    {
        $this->repository = $repository;
        $this->commonFilterRepository = $commonFilterRepository;
        $this->reportOutputData = $reportOutputData;
    }

    /**
     * generates collection data for report
     */
    public function data()
    {
        $requestedData = request()->form;
        $inputData = $this->getInputData($requestedData);

        if (!$inputData['isValid']) {
            return ['assets' => collect(), 'count' => 0];
        }
        $assets = $this->repository->getData();
        $assets = $this->filterWithInputData($assets, $inputData);
        $count  = $assets->count();
        $assets = $this->reportOutputData->getOutputData($assets, ['created_at' => 'desc']);

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

    /**
     * Retrieves the input data based on the requested data.
     *
     * @param array $requestedData The array of requested data.
     * @return array The filtered input data.
     */
    public function getInputData(array $requestedData): array
    {
        $filter = [
            'month' => $requestedData['month'] ?? '',
            'year' => $requestedData['year'] ?? '',
            'collection_status' => $requestedData['collection_status'] ?? '',
            'type' => $requestedData['type'] ?? '',
        ];

        if ($filter['type'] !== null) {
            $filter = $this->getCollectionStatusAndYear($filter['type'], $filter);
        }
        $filter['isValid'] = true;

        if (empty($filter['collection_status']) || empty($filter['month']) || empty($filter['year'])) {
            $filter['isValid'] = false;
        }

        return $filter;
    }

    /**
     * Filter the query results based on the filters applied
     *
     * @return object
     */
    public function filterWithInputData($query, array $inputData)
    {
        $query = $this->commonFilterRepository->filterWithDirectFields($query, 'collection_status', $inputData['collection_status']);
        $query = $this->commonFilterRepository->filterWithDirectFields($query, 'year', $inputData['year']);
        $query = $this->commonFilterRepository->filterWithDirectFields($query, 'month', $inputData['month']);

        return $query;
    }

    /**
     * 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($termAsset): array
    {
        $nestedData = [];
        $nestedData['report']['serial_no']          = $nestedData['export']['Serial #'] = disableCSVInjection($termAsset->asset?->serial_no);
        $nestedData['report']['asset_tag']          = $nestedData['export']['Asset Tag #'] = disableCSVInjection($termAsset->asset?->asset_tag);
        $nestedData['report']['hardware']           = $nestedData['export']['Hardware Standard'] = disableCSVInjection($termAsset->asset?->makeAndModel?->name);
        $nestedData['report']['status']             = $nestedData['export']['Status'] = disableCSVInjection($termAsset->asset?->assetStatus?->name);
        $nestedData['report']['user']               = $nestedData['export']['User Name'] = disableCSVInjection($termAsset->user?->user_name);
        $nestedData['report']['email']              = $nestedData['export']['Email'] = disableCSVInjection($termAsset->user?->email);
        $nestedData['report']['ticket_no']          = $nestedData['export']['Assignment Ticket #'] = disableCSVInjection($termAsset->asset?->latestUpdatedAssetHistory?->ticket_no);
        $nestedData['report']['updated_at']         = $nestedData['export']['Last Modified Date'] = disableCSVInjection($termAsset->asset?->latestAssetHistory ? ($termAsset->asset->latestAssetHistory->updated_at) : date('m/d/Y', strtotime($termAsset->asset->updated_at->toDateString())));

        return $nestedData;
    }

    /**
     * Get nested data for the given item and index.
     *
     * @param mixed $item The item to retrieve nested data for.
     * @param mixed $index The index for the nested data.
     * @return array The nested data for the given item and index.
     */
    public function getNestedData($item, $index)
    {
        $nestedData = [];
        $commonData = $this->getReportNestedData($item);
        $nestedData = $commonData['report'];
        $nestedData['id'] = $index;
        $nestedData['asset_tag'] = generateAssetLink($item->asset?->id, $item->asset?->asset_tag);
        $nestedData['serial_no'] = generateAssetLink($item->asset?->id, $item->asset?->serial_no);
        $nestedData['user'] = generateUserLink($item?->user?->id, $item?->user?->user_name);

        return $nestedData;
    }

    /**
     * Finds the collection status and year based on given value
     * @param int $type  selected bar number of graph
     * @param array $filterArray  the array to which values should be added
     * @return array $filterArray
     */
    public function getCollectionStatusAndYear($type, $filterArray)
    {
        $thisYear = Carbon::now()->format('Y');

        //current year - devices uncollected
        if ($type == 1) {
            $filterArray['year'] = $thisYear;
            $filterArray['collection_status'] = 'uncollected';

            return $filterArray;
        }

        //current year - devices collected
        if ($type == 2) {
            $filterArray['year'] = $thisYear;
            $filterArray['collection_status'] = 'collected';

            return $filterArray;
        }

        //previous year - devices uncollected
        if ($type == 3) {
            $filterArray['year'] = $thisYear - 1;
            $filterArray['collection_status'] = 'uncollected';

            return $filterArray;
        }

        //previous year - devices collected
        if ($type == 4) {
            $filterArray['year'] = $thisYear - 1;
            $filterArray['collection_status'] = 'collected';

            return $filterArray;
        }

        return $filterArray;
    }

    /**
     * Returns month number from month name
     * @param string $month
     * @return int month number
     */
    function getMonth($month)
    {
        if (in_array(date('F', strtotime($month)), config('months'))) {
            return date('m', strtotime($month));
        }

        return null;
    }

    public function exportData()
    {
        $requestedData = request()->all();
        $inputData = $this->getInputData($requestedData);

        if (!$inputData['isValid']) {
            return collect();
        }
        $assets = $this->repository->getData();
        $assets = $this->filterWithInputData($assets, $inputData);
        $assets = $assets->orderBy('id', 'desc');

        return $assets;
    }

    /**
     * returns the values of selected bar from HR collection graph
     */
    public function getFilters()
    {
        $filter = [];
        $filter['month'] = $this->getMonth(request('month'));
        $filter['year'] = '';
        $filter['collection_status'] = '';
        $type = request('type') ?? '';

        if ($type !== null) {
            $filter = $this->getCollectionStatusAndYear($type, $filter);
        }

        return $filter;
    }

    /**
     * update assets collection details for selected report
     */
    public function updateCollectionDataByFilters()
    {
        $requestedData = request()->all();
        $filters = $this->getInputData($requestedData);

        if ($filters['collection_status'] == 'collected') {
            $assets = $this->repository->getCollectedAssets();
        } elseif ($filters['collection_status'] == 'uncollected') {
            $assets = $this->repository->getUnCollectedAssets();
        }

        $date = Carbon::createFromDate($filters['year'], $filters['month'], 1);
        $firstDay = $date->format('Y-m-d');
        $lastDay = $date->endOfMonth()->format('Y-m-d');
        $assets = $this->repository->filterAssetsByTerminatedDateRange($assets, $firstDay, $lastDay, $filters['type']);
        $assets = $assets->orderByDesc('created_at')->get();

        if ($assets) {
            $this->saveCollectionDetails($assets, $filters['year'], $filters['month'], $filters['collection_status'], $filters['type']);
        }

        return true;
    }

    /**
     * save collection details of assets
     * @param array $assets
     * @param int $year
     * @param int $month
     * @param string $status  collection status of asset
     * @param string $reportType type of collection report
     *
     * @return void
     */
    public function saveCollectionDetails($assets, $year, $month, $status, $reportType)
    {
        $this->repository->saveCollectionDetails($assets, $year, $month, $status, $reportType);
    }
}
