<?php

namespace App\Services\Api;


use App\Models\Location;
use Validator;
use Carbon\Carbon;
use App\Events\BulkUpdates;
use App\Models\LocationType;
use App\Models\SiteCode;
use Auth;

/**
 * Class LocationCreateApiService
 *
 * Service class for creating and validating location data from API requests.
 */
class LocationCreateApiService extends ApiService
{
    /**
     * Get and prepare location data from the request.
     *
     * @return array|bool Location data array or false if validation fails.
     */
    public function getData()
    {
        $inputData = request()->all();

        $locationData = $this->initializeLocationData($inputData);


        $relationalValues = ['location_type', 'site_code'];

        $this->populateLocationTypeData($inputData, $locationData);
        $this->populateSiteCodeData($inputData, $locationData);

        $hasRelationalValues = array_intersect_key(array_flip($relationalValues), $inputData);
        if (empty($hasRelationalValues)) {
            return $locationData;
        }

        return $locationData;
    }

    /**
     * Validate the fields from the request.
     *
     * @return \Illuminate\Contracts\Validation\Validator|null Validation errors or null if validation succeeds.
     */
    public function validateFields()
    {
        $rules = [
            'location_type' => 'required|exists:location_types,location_type_name',
            'room_name'     => 'required|unique:locations',
            'site_code'     => 'nullable|exists:site_codes,code',
            'room_capacity' => 'nullable|integer',
            'status' => 'nullable|in:Active,Inactive'
        ];

        $messages = [
            'location_type.required' => 'The Location Type is required.',
            'room_name.required'     => 'The Room Name is required.',
            'room_name.unique'       => 'The Room Name has already been taken.',
            'location_type.exists'   => 'The Location Type does not exist.',
            'site_code.exists'       => 'The Site Code does not exist.',
        ];

        $validator = Validator::make(request()->all(), $rules, $messages);

        return $validator->fails() ? $validator->errors() : null;
    }

     /**
     * Save location data to the database.
     *
     * @param array $locationData Location data to be saved.
     *
     * @return void
     */
    public function saveData($locationData)
    {
        Location::updateorCreate(['room_name' => $locationData['room_name']], $locationData);

        $this->saveLocationHistory($locationData);
    }

    /**
     * Save location history information.
     *
     * @param array $data Location data.
     *
     * @return void
     */
    public function saveLocationHistory(array $data)
    {
        $description = $this->generateAssetHistoryDescription($data);

        $assetHistory = [
            'user_id' => Auth::id(),
            'action' => 'location_added',
            'description' => $description,
            'created_at'  => Carbon::now()->format('Y-m-d H:i:s'),
            'updated_at'  => Carbon::now()->format('Y-m-d H:i:s'),
        ];

        event(new BulkUpdates($assetHistory));
    }

    /**
     * Generate the description for location history.
     *
     * @param array $data Location data.
     *
     * @return string Description.
     */
    private function generateAssetHistoryDescription(array $data)
    {
        return  __('history.LocationCreated', [
            'roomName' => $data['room_name']
        ]);
    }

    /**
     * Initialize location data from the input data.
     *
     * @param array $inputData Input data.
     *
     * @return array Initialized location data.
     */
    private function initializeLocationData($inputData)
    {
        $directValues = [
            'room_name', 'address', 'building', 'floor', 'status', 'room_capacity'
        ];

        $locationData = array_fill_keys($directValues, '');

        foreach ($inputData as $key => $value) {
            if (in_array($key, $directValues)) {
                $locationData[$key] = $value;
            }
        }

        if (empty($locationData['status']) || strtolower($locationData['status']) === 'active') {
            $locationData['status'] = 1;
        } elseif (strtolower($locationData['status']) === 'inactive') {
            $locationData['status'] = 0;
        } else {
            $locationData['status'] = 1;
        }

        return $locationData;
    }

    /**
     * Populate location type data in the location data array.
     *
     * @param array $inputData
     * @param array $locationData
     *
     * @return void
     */
    private function populateLocationTypeData($inputData, &$locationData)
    {
        if (array_key_exists('location_type', $inputData)) {
            $locationType = LocationType::getFromName(request('location_type'))->first();
            $locationTypeId = $locationType ? $locationType->id : null;
            $locationData['location_type_id'] = $locationTypeId;
        }
    }

    /**
     * Populate site code data in the location data array.
     *
     * @param array $inputData
     * @param array $locationData
     *
     * @return void
     */
    private function populateSiteCodeData($inputData, &$locationData)
    {
        if (array_key_exists('site_code', $inputData)) {
            $siteCode = SiteCode::getFromCode(request('site_code'))->first();

            if ($siteCode) {
                $locationData['site_code_id'] = $siteCode->id ?? null;
                $locationData['region_id'] = $siteCode->region_id ?? null;
                $locationData['country_id'] = $siteCode->country_id ?? null;
            }
        }
    }
}
