<?php

namespace App\Services\Settings;

use App\Events\BulkUpdates;
use App\Models\AssetType;
use App\Models\MakeAndModel;
use App\Models\Manufacturer;
use App\Models\TechnicalSpecs;
use Carbon\Carbon;
use Exception;
use Illuminate\Support\Facades\Auth;

/**
 * Service Class for HardwareStandard Export
 */
class HardwareStandardService

{

    /**
     * Retrieve hardware standards along with related manufacturers and asset types, and count of associated assets.
     *
     * @return \Illuminate\Database\Eloquent\Builder The query builder with the specified relationships and counts.
     */
    public function getHardwareStandards()
    {
        return MakeAndModel::with(['manufacturer:id,name', 'assetType:id,name'])
            ->withCount('assets')
            ->join('asset_types', 'make_and_models.asset_type_id', '=', 'asset_types.id')
            ->join('manufacturers', 'make_and_models.manufacturer_id', '=', 'manufacturers.id');
    }

    /**
     * Filter the hardware standards based on asset type and manufacturer from request parameters.
     *
     * @param \Illuminate\Database\Eloquent\Builder $hardwares The query builder for hardware standards.
     *
     * @return \Illuminate\Database\Eloquent\Builder The filtered query builder.
     */
    public function filterHardwareStandards($hardwares)
    {
        $assetType = request('asset_type');
        $manufacturer = request('manufacturer');

        if ($assetType) {
            $hardwares = $hardwares->whereIn('asset_type_id', $assetType);
        }

        if ($manufacturer) {
            $hardwares = $hardwares->whereIn('manufacturer_id', $manufacturer);
        }

        return $hardwares;
    }

    /**
     * Retrieve hardware standard data, starting from a given index, and appending nested data for each spec.
     *
     * @param array $specs The list of hardware specifications to process.
     * @param int   $start The starting index.
     * @param array $data  The initial data array to which the nested data will be appended.
     *
     * @return array The updated data array with nested hardware standard data.
     */
    public function getHardwareStandardData($specs, $start, $data)
    {
        $parentIndex = $start;

        foreach ($specs as $spec) {
            $parentIndex++;
            $nestedData = $this->getExportNestedData($spec);
            $data[] = $nestedData;
        }

        return $data;
    }

    /**
     * Retrieve nested data for a given hardware specification.
     *
     * @param object $hardware The hardware specification object containing details of the hardware.
     *
     * @return array An associative array containing the asset type, manufacturer, hardware standard, and number of assets.
     */
    public function getExportNestedData($hardware)
    {
        $nestedData['Asset Type']        = optional($hardware->assetType)->name;
        $nestedData['Manufacturer']      = optional($hardware->manufacturer)->name;
        $nestedData['Hardware Standard'] = optional($hardware)->name;
        $nestedData['No Of Assets']      = optional($hardware->assets)->count();

        return $nestedData;
    }

    /**
     * Update a hardware standard with new details from the request.
     *
     * @param \Illuminate\Http\Request $request The request object containing the updated details.
     *
     * @return bool True if the update was successful, false otherwise.
     */
    public function updateHardwareStandard($request)
    {
        try {
            $oldHardware = MakeAndModel::with(['manufacturer', 'assetType'])->where('id', $request->make_and_model_id)->first();

            $manufacturer = $request->manufacturer_name;
            $manufacturer_id = Manufacturer::updateOrCreate(
                ['slug' => str_slug($manufacturer, '_')],
                ['name' => $manufacturer]
            )->id;

            $assetType = AssetType::where('name', trim($request->assettype))->first();
            $assettype_id = $assetType->id;

            $makeModelName = $request->make_model_name;

            MakeAndModel::findOrFail($request->make_and_model_id)
                ->update([
                    'manufacturer_id' => $manufacturer_id,
                    'name' => $makeModelName,
                    'slug' => str_slug($makeModelName, '_'),
                    'asset_type_id' => $assettype_id,
                ]);

            $this->createHardwareStandardUpdateHistory($oldHardware, $request);

            return true;
        } catch (Exception $e) {
            return false;
        }
    }

    /**
     * Create a history record for a hardware standard update, detailing changes in manufacturer, asset type, and name.
     *
     * @param object                   $oldHardware The original hardware details before the update.
     * @param \Illuminate\Http\Request $request     The request object containing the updated details.
     *
     * @return bool True if the history record was successfully created.
     */
    private function createHardwareStandardUpdateHistory($oldHardware, $request)
    {
        $oldManufactureName  = $oldHardware->manufacturer ? optional($oldHardware->manufacturer)->name : "";
        $oldAssetType        = $oldHardware->assetType ? optional($oldHardware->assetType)->name : "";
        $oldName             = $oldHardware->name;

        $newAssetType        = $request->assettype;
        $newManufactureName  = $request->manufacturer_name;
        $newName             = $request->make_model_name;

        $description = '';

        if ($oldManufactureName != $newManufactureName) {
            $description .= __('history.FieldsUpdated', [
                'fieldName' => 'Manufacturer',
                'oldValue'    => $oldManufactureName,
                'newValue'  => $newManufactureName,
            ]);
        }

        if ($oldName != $newName) {
            $description .= __('history.FieldsUpdated', [
                'fieldName' => 'Make and Model',
                'oldValue'    => $oldName,
                'newValue'  => $newName,
            ]);
        }

        if ($oldAssetType != $newAssetType) {
            $description .= __('history.FieldsUpdated', [
                'fieldName' => 'Asset Type',
                'oldValue'    => $oldAssetType,
                'newValue'  => $newAssetType,
            ]);
        }

        $description = __('history.HardwareStandardUpdated', [
            'description' => $description
        ]);

        $assetHistory = [
            'user_id' => Auth::id(),
            'action' => 'hardware_standard_updated',
            '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));

        return true;
    }

    /**
     * Delete a hardware standard if it has no associated assets and create a history record for the deletion.
     *
     * @param int $makeAndModelId The ID of the hardware standard to be deleted.
     *
     * @return bool True if the hardware standard was successfully deleted, false otherwise.
     */
    public function deleteHardwareStandard($makeAndModelId)
    {
        $hardwareStandard = MakeAndModel::with('manufacturer')->findOrFail($makeAndModelId);
        $manufacturerName = $hardwareStandard->manufacturer ? $hardwareStandard->manufacturer->name : "";
        $hardwareStandardText = $manufacturerName . ' ' . $hardwareStandard->name;

        if ($hardwareStandard->assets->count()) {
            return false;
        }

        $hardwareStandard->delete();
        TechnicalSpecs::where('make_and_model_id', $makeAndModelId)->delete();

        $description = __('history.HardwareStandardDeleted', [
            'hardwareStandard' => $hardwareStandardText
        ]);

        $assetHistory = [
            'user_id' => Auth::id(),
            'action' => 'hardware_standard_deleted',
            '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));

        return true;
    }
}
