<?php

namespace App\Services\InventoryConsumption;

use App\Models\Country;
use App\Models\Location;
use App\Models\Region;
use App\Repositories\InventoryConsumption\ConsumptionReportRepository;
use App\Repositories\CommonFilterRepository;
use App\Http\Responses\ReportOutputData;
use App\Services\Reports\AbstractReportService;
use Carbon\Carbon;

/**
 * Service Class for Consumption Trends Report
 */
class ConsumptionTrendsService extends AbstractReportService
{
    protected $repository;
    protected $commonFilterRepository;
    protected $reportOutputData;

    /**
     * Constructor for ConsumptionReportService.
     *
     * @param ConsumptionReportRepository $consumptionReportRepository The repository instance.
     * @param CommonFilterRepository $commonFilterRepository The repository for the CommonFilter entity.
     * @param ReportOutputData $reportOutputData The ReportOutputData entity
     */
    public function __construct(ConsumptionReportRepository $consumptionReportRepository, CommonFilterRepository $commonFilterRepository, ReportOutputData $reportOutputData)
    {
        $this->repository = $consumptionReportRepository;
        $this->commonFilterRepository = $commonFilterRepository;
        $this->reportOutputData = $reportOutputData;
    }

    /**
     * Get the count of consumption trend data.
     *
     * @return array
     */
    public function getCountOfConsumptionTrend()
    {
        $counts = [];
        $queryConditionsData = $this->repository->getQueryConditionsData();

        for ($i = 0; $i < 12; $i++) {
            $startDate = date('Y-m-01 00:00:00', strtotime("-$i months"));
            $endDate = date('Y-m-t 23:59:59', strtotime("-$i months"));

            $assets = $this->getConsumptionTrendData($queryConditionsData, $startDate, $endDate);
            $counts[] = $assets->count();
        }
        $data = array_reverse($counts);

        return compact('data');
    }


    /**
     * Retrieves consumption trend data based on query conditions and date range.
     *
     * @param array $queryConditionsData The query conditions data
     * @param string $startDate The start date
     * @param string $endDate The end date
     * @return object The consumption trend data
     */
    public function getConsumptionTrendData($queryConditionsData, $startDate, $endDate)
    {
        $inputData = $this->getInputData();
        $assets = $this->repository->getCountOfConsumptionTrend($queryConditionsData, $startDate, $endDate);
        $assets = $this->commonFilterRepository->filterWithDirectFields($assets, 'old_location_id', $inputData['location']);
        $assets = $this->commonFilterRepository->filterWithWhereHasRelationFields($assets, 'oldLocation.siteCode', 'country_id', $inputData['country']);
        $assets = $this->commonFilterRepository->filterWithWhereHasRelationFields($assets, 'oldLocation.siteCode', 'region_id', $inputData['region']);
        
        return $assets;
    }

    /**
     * Get the input data for filtering.
     *
     * @return array
     */
    public function getInputData()
    {
        $requestedData = request()->form ?? request()->all();

        return [
            'location' => $requestedData['selected_location'] ?? [],
            'country' => $requestedData['selected_country'] ?? [],
            'region' => $requestedData['selected_region'] ?? [],
            'date' => $requestedData['date'] ?? '',
        ];
    }

    /**
     * Get the options data for filter dropdown.
     * 
     * @return array
     */
    public function getFilterDataOptions()
    {
        $filterDataOptions['locations'] = Location::select('id', 'room_name')
            ->warehouses()
            ->orderBy('room_name')
            ->get();
        $filterDataOptions['countries'] = Country::select('id', 'name')
            ->orderBy('name')
            ->get();
        $filterDataOptions['regions'] = Region::select('id', 'name')
            ->orderBy('name')
            ->get();

        return $filterDataOptions;    
    }

    /**
     * Get data for the report table.
     *
     * @return array
     */
    public function data()
    {
        $inputData = $this->getInputData();
        $queryConditionsData = $this->repository->getQueryConditionsData();
        $startDate = $this->getFromDate($inputData);
        $endDate = $this->getToDate($inputData);
        $assets = $this->getConsumptionTrendData($queryConditionsData, $startDate, $endDate);
        $count  = $assets->count();
        $assets = $this->reportOutputData->getOutputData($assets, ['asset_histories.created_at' => 'desc']);

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


    /**
     * Get the start of date range
     * @return Carbon
     */
    public function getFromDate($inputData)
    {
        $date = $inputData['date'] ?? '';

        if (!empty($date)) {
            $dateFrom = Carbon::createFromFormat("M Y", $date)->startOfMonth();
            
            return $dateFrom;
        } 
        
        return first_day_current_month_past_year(1);
    }

    /**
     * Get the end of date range
     * @return Carbon
     */
    public function getToDate($inputData)
    {
        $date = $inputData['date'] ?? '';

        if (!empty($date)) {
            $dateFrom = Carbon::createFromFormat("M Y", $date)->endOfMonth();

            return $dateFrom;
        }
        
        return first_day_current_month_future_year(0);
    }

    /**
     * Retrieves nested data for a given asset and index.
     *
     * @param mixed $item The asset object.
     * @param int $index The index of the nested data.
     *
     * @return array The nested data.
     */
    public function getNestedData($item, $index)
    {
        $commonData = $this->getReportNestedData($item);
        $nestedData = $commonData['report'];
        $userLocationLink = $item->newUser ? generateUserLink($item->newUser?->id, $nestedData['userlocation']) : generateLocationLink($item->newLocation?->id, $nestedData['userlocation']);

        $nestedData['id']   = $index;
        $nestedData['asset_tag'] = generateAssetLink($item->asset->id, $nestedData['asset_tag']);
        $nestedData['serial_no'] = generateAssetLink($item->asset?->id, $nestedData['serial_no']);
        $nestedData['userlocation'] = $userLocationLink;
        $nestedData['storage_location'] = generateLocationLink($item->oldLocation?->id, $nestedData['storage_location']);
        $nestedData['last_modified_by'] = generateUserLink($item->asset?->latestAssetHistory?->user?->id, $nestedData['last_modified_by']);

        return $nestedData;
    }

    /**
     * Retrieves the export data based on the input data.
     *
     * @return mixed The export data.
     */
    public function exportData()
    {
        //
    }

    /**
     * Returns an array of nested data for exporting.
     *
     * @param mixed $asset The asset object.
     * @return array The nested data array.
     */
    public function getReportNestedData($assetHistory)
    {
        $nestedData = [];
        $nestedData['report']['asset_tag']          = $nestedData['export']['Asset Tag #'] = disableCSVInjection(optional($assetHistory->asset)->asset_tag ?? '');
        $nestedData['report']['serial_no']          = $nestedData['export']['Serial #'] = disableCSVInjection(optional($assetHistory->asset)->serial_no ?? '');
        $nestedData['report']['asset_type']         = $nestedData['export']['Asset Type'] = disableCSVInjection(optional(optional($assetHistory->asset)->assetType)->name ?? '');
        $nestedData['report']['hardware_standard']  = $nestedData['export']['Hardware Standard'] = disableCSVInjection(optional(optional($assetHistory->asset)->makeAndModel)->name ?? '');
        $nestedData['report']['tech_specs']         = $nestedData['export']['Technical Specs'] = disableCSVInjection(optional(optional($assetHistory->asset)->technicalSpec)->details ?? '');
        $nestedData['report']['asset_status'] = $nestedData['export']['Asset Status'] = disableCSVInjection(optional(optional($assetHistory->asset)->assetStatus)->name ?? '');
        $nestedData['report']['prev_asset_status'] = $nestedData['export']['Previous Asset Status'] = disableCSVInjection($assetHistory->oldStatus?->name);
        $nestedData['report']['userlocation'] = $nestedData['export']['User/Location'] = disableCSVInjection($assetHistory->newUser ? (optional($assetHistory->newUser)->email) : ($assetHistory->newLocation ? (optional($assetHistory->newLocation)->room_name) : ''));
        $nestedData['report']['storage_location'] = $nestedData['export']['Storage Location'] = disableCSVInjection(optional($assetHistory->oldLocation)->room_name ?? '');
        $nestedData['report']['storage_country'] = $nestedData['export']['Storage Country'] = disableCSVInjection(optional(optional(optional($assetHistory->oldLocation)->siteCode)->country)->name ?? '');
        $nestedData['report']['storage_region'] = $nestedData['export']['Storage Region'] = disableCSVInjection(optional(optional(optional($assetHistory->oldLocation)->siteCode)->region)->name ?? '');
        $nestedData['report']['date_assigned'] = $nestedData['export']['Date Assigned'] = disableCSVInjection($assetHistory->created_date);
        $nestedData['report']['created_date'] = $nestedData['export']['Created Date'] = disableCSVInjection(optional($assetHistory->asset)->created_at ?? '');
        $nestedData['report']['last_modified_by'] = $nestedData['export']['Last Modified By'] = disableCSVInjection(optional(optional(optional($assetHistory->asset)->latestAssetHistory)->user)->email ?? '');

        return $nestedData;
    }

}
