<?php

namespace App\Services\Terminations\HrCollection;

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

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

    /**
     * Initializes a new instance of the class.
     *
     * @param RetrievalStatisticsRepository $repository The retrieval statistics repository.
     * @param CommonFilterRepository $commonFilterRepository The common filter repository.
     * @param ReportOutputData $reportOutputData The report output data.
     */
    public function __construct(RetrievalStatisticsRepository $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->getReportListData($inputData);
        $assets = $this->filterWithInputData($assets, $inputData);
        $count  = $assets->count();
        $assets = $this->reportOutputData->getOutputData($assets, ['id' => 'asc']);

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

    /**
     * Filter the query results based on the filters applied
     *
     * @param  mixed $assets
     * @param  mixed $inputData
     * @return object
     */
    public function filterWithInputData($query, $inputData)
    {
        if ($inputData['type'] == 1) {
            $query = $this->commonFilterRepository->filterWithRelationalDateRange($query, 'newUser', 'terminated_date', $inputData['termination_start_date'], $inputData['termination_end_date']);
            $query = $this->commonFilterRepository->searchToMultipleFieldsWithRelation($query, 'newUser', ['first_name', 'last_name', 'email', 'employee_id'], $inputData['user_search_text']);
            $query = $this->commonFilterRepository->filterWithWhereHasRelationFields($query, 'newUser', 'user_type_id', $inputData['employee_type']);
            $query = $this->commonFilterRepository->filterWithWhereHasRelationFields($query, 'newUser', 'department_id', $inputData['department']);
            $query = $this->commonFilterRepository->filterWithWhereHasRelationFields($query, 'newUser', 'city', $inputData['work_location']);
        } else {
            $query = $this->commonFilterRepository->filterWithRelationalDateRange($query, 'oldUser', 'terminated_date', $inputData['termination_start_date'], $inputData['termination_end_date']);
            $query = $this->commonFilterRepository->searchToMultipleFieldsWithRelation($query, 'oldUser', ['first_name', 'last_name', 'email', 'employee_id'], $inputData['user_search_text']);
            $query = $this->commonFilterRepository->filterWithWhereHasRelationFields($query, 'oldUser', 'user_type_id', $inputData['employee_type']);
            $query = $this->commonFilterRepository->filterWithWhereHasRelationFields($query, 'oldUser', 'department_id', $inputData['department']);
            $query = $this->commonFilterRepository->filterWithWhereHasRelationFields($query, 'oldUser', 'city', $inputData['work_location']);
        }
        $query = $this->repository->filterQueryForAssetsByType($query, $inputData['type']);
        $query = $this->commonFilterRepository->filterWithWhereHasRelationFields($query, 'asset', 'asset_tag', $inputData['asset_tag']);
        $query = $this->commonFilterRepository->filterWithWhereHasRelationFields($query, 'asset', 'serial_no', $inputData['serial_no']);

        return $query;
    }

    /**
     * get input data
     * @params
     * @return array
     * */
    public function getInputData($requestedData)
    {
        $month = $requestedData['month'] ?? '';
        $year = $requestedData['year'] ?? date('Y');
        $date = Carbon::createFromDate($year, $month, 1);
        $firstDay = $date->format(config('date.formats.read_date_format'));
        $lastDay = $date->endOfMonth()->format(config('date.formats.read_date_format'));

        return [
            'type' => $requestedData['type'] ?? '',
            'termination_start_date' => $firstDay,
            'termination_end_date' => $lastDay,
            'user_search_text' => $requestedData['employee_name'] ?? '',
            'employee_type' => $requestedData['employee_type'] ?? '',
            'department' => $requestedData['department'] ?? '',
            'work_location' => $requestedData['work_location'] ?? '',
            'asset_tag' => $requestedData['asset_tag'] ?? '',
            'serial_no' => $requestedData['serial_no'] ?? '',
        ];
    }

    /**
     * Create output data
     * @params $assets,$start, $data, $type
     * @return array
     * */
    public function getOutputData($assets, $data)
    {
        $parentIndex = 0;

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

        return $data;
    }

    /**
     * get Report and export common Nested Data
     *
     * @param  mixed $history
     * @return void
     */
    public function getReportNestedData($data)
    {
        $nestedData = [];
        $user = $data->newUser ?? $data->oldUser;
        $asset = $data->asset;
        $assetReturnedHistory = $this->repository->getAssetReturnedHistory($asset->id, $user?->id, $user?->terminated_date);
        $nextStatusAfterAssigned = $this->repository->getNextStatusAfterAssigned($asset?->id, $user?->id);
        $noOfDays = $this->getNoOfDays($user, $nextStatusAfterAssigned);

        $nestedData['report']['asset_tag']          = $nestedData['export']['Asset Tag #'] = disableCSVInjection($data->asset?->asset_tag);
        $nestedData['report']['serial_no']          = $nestedData['export']['Serial #'] = disableCSVInjection($data->asset?->serial_no);
        $nestedData['report']['user_name']          = $nestedData['export']['User Name'] = disableCSVInjection($user?->first_name . ' ' . $user?->last_name);
        $nestedData['report']['termination_date']   = $nestedData['export']['Termination Date'] = disableCSVInjection($user?->terminated_date);
        $nestedData['report']['returned_date']      = $nestedData['export']['Returned Date'] = disableCSVInjection(parse_date_from_db_datetime($assetReturnedHistory?->getRawOriginal('created_at')));
        $nestedData['report']['status_changed_to']  = $nestedData['export']['Status Changed To'] = disableCSVInjection($nextStatusAfterAssigned->newStatus->name ??  $asset->assetStatus?->name);
        $nestedData['report']['no_of_days']         = $nestedData['export']['# of Days'] = disableCSVInjection($noOfDays);
        $nestedData['report']['user_title']         = $nestedData['export']['Title'] = disableCSVInjection($user->business_title);
        $nestedData['report']['department']         = $nestedData['export']['Department'] = disableCSVInjection($user?->department?->name);
        $nestedData['report']['work_location']      = $nestedData['export']['Work Location'] = disableCSVInjection($user?->city);
        $nestedData['report']['storage_room']       = $nestedData['export']['Storage Room'] = disableCSVInjection($asset?->location?->room_name);
        $nestedData['report']['ticket_no']          = $nestedData['export']['Ticket #'] = disableCSVInjection($data->ticket_no);
        $nestedData['report']['modified_date']      = $nestedData['export']['Modified Date'] = disableCSVInjection(parse_date_from_db_datetime($data?->getRawOriginal('created_at')));
        $nestedData['report']['modified_by']        = $nestedData['export']['Modified by'] = disableCSVInjection($data?->user?->first_name . ' ' . $data?->user?->last_name);

        return $nestedData;
    }

    /**
     * Create each row of output data
     * @params $assets,$index,$type
     * @return array
     * */
    public function getNestedData($item, $index)
    {
        $nestedData = [];
        $commonData = $this->getReportNestedData($item);
        $nestedData = $commonData['report'];
        $user = $item->newUser ?? $item->oldUser;
        $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_name'] = generateUserLink($user?->id, $user?->user_name);
        $nestedData['storage_room'] = generateLocationLink($item->asset?->location?->id, $nestedData['storage_room']);
        $nestedData['modified_by'] = generateUserLink($item->user?->id, $item->user?->user_name);

        return $nestedData;
    }

    /**
     * Exports 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');

        return $assets;
    }

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

        return $filter;
    }

    /**
     * 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;
    }

    /**
     * Calculates the number of days between the termination date of the old user
     * and the creation date of the next status after being assigned.
     *
     * @param mixed $data The data containing the old user and the next status.
     * @param mixed $nextStatusAfterAssigned The next status after being assigned.
     * @return int The number of days between the termination date and the creation date.
     */
    public function getNoOfDays($user, $nextStatusAfterAssigned)
    {
        if (!empty($user->terminated_date) && !empty($nextStatusAfterAssigned)) {
            return Carbon::parse($nextStatusAfterAssigned->getRawOriginal('created_at'))->diffInDays($user->getRawOriginal('terminated_date'));
        }

        return 0;
    }
}
