<?php

namespace App\Services\BulkUpload;

use App\Events\BulkUpdates;
use App\Models\AssetStatus;
use App\Models\MakeAndModel;
use App\Models\TechnicalSpecs;
use App\Services\Integrations\Tickets\TicketManagementService;
use Carbon\Carbon;
use Facades\App\Repositories\BulkUpload;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

class BulkTechnicalSpecsService extends BulkAbstract
{
    public function __construct(protected TicketManagementService $ticketManagementService) {}

    /**
     * Return the view for displaying errors or data
     * @param  string $path
     * @return json
     */
    public function getViewData(string $path, $fileName)
    {
        $data = $this->importAssetData($path);
        if ($view = $this->handleImportErrors($data)) {
            return response()->json($view);
        }

        $csvData = $data['csvData'];

        if ($view = $this->handleCsvColumnErrors($path, $csvData)) {
            return response()->json($view);
        }

        if ($csvData) {

            $validatedData = $this->validateFields($csvData);

            $errors = $validatedData['errors'];
            $csvData = $validatedData['csvData'];

            $view['errors'] = view('assets.partials.upload-errors', compact('errors'))->render();

            $view['data'] = $this->renderCsvData($csvData, $path, $fileName);
            $view['countVal'] = count($csvData);
        }

        return response()->json($view);
    }

    /**
     * Renders the CSV data into a view and returns the rendered content.
     *
     * @param array $csvData The CSV data to be rendered.
     * @param string $path The path of the file.
     * @param string $fileName The name of the file.
     * @return string The rendered content of the view.
     */
    public function renderCsvData($csvData, $path, $fileName)
    {
        return view('settings.partials.uploaded-technical-specs', compact('csvData', 'path', 'fileName'))->render();
    }

    /**
     * Generate asset data from the csv array
     * @param array $item
     * @param  int   $count
     * @return array
     */
    public function generateCSVData($item, int $count, $path = null, $fileName = null)
    {
        $assetData    = [];
        $assetData = array_combine(
            array_map(fn($key) => str_slug($key, '_'), array_keys($item)),
            $item
        );
        foreach ($this->getHeaderMap() as $dbField => $fileHeader) {
            $result = $this->getRelationalValues($item, $dbField, $fileHeader);
            if ($result !== false) {
                $item[$fileHeader] = $result;
            }
            $assetData[$dbField] = !empty($item[$fileHeader]) ? trim($item[$fileHeader]) : null;
        }
        if ($fileName && $path) {
            $assetData['filePath'] = $path;
            $assetData['fileName'] = $fileName;
        }

        $assetData['asset_count'] = $count++;
        session(['asset_count' => $assetData['asset_count']]);
        return compact('assetData');
    }

    /**
     * Get Related Values for ids.
     * @param  string $item
     * @param  string $dbField
     * @param  string $fileHeader
     *
     * @return mixed
     */
    public function getRelationalValues($item,  $dbField,  $fileHeader)
    {
        if ($dbField == "make_and_model_id") {
            return BulkUpload::getAttributeMakeModelId($item, $dbField, $fileHeader);
        }

        if ($dbField == "technical_spec_id") {
            $techSpec = TechnicalSpecs::where(['make_and_model_id' => $item['Hardware Standard'] ?? 0, 'details' => $item['Current Technical Specs']])->first();
            return $techSpec->id ?? null;
        }

        return false;
    }

    public function csvValidator($data, $count)
    {
        $validator = Validator::make(
            $data,
            [
                'make_and_model_id' => ['required'],
                'technical_spec_id' => [Rule::requiredIf(function () use ($data) {
                    return !empty($data['current_technical_specs']);
                })],
                'new_technical_specs' => ['required'],
                'original_value' => [Rule::requiredIf(function () use ($data) {
                    return !empty($data['current_technical_specs']);
                })],
                'status' => ['nullable', Rule::in(['Active', 'Inactive'])]
            ],
            [
                'make_and_model_id.required'    => 'Line no ' . $count . ' The hardware standard does not exist.',
                'technical_spec_id.required'    => 'Line no ' . $count . ' The technical spec does not exist for the hardware standard.',
                'new_technical_specs.required'    => 'Line no ' . $count . ' : The new technical specs is required.',
                'original_value.required'    => 'Line no ' . $count . ' The original value is required.',
                'status.in' => 'Line no ' . $count . ' : The status must be either "Active" or "Inactive".',
            ]
        );

        if ($validator->fails()) {
            return $validator->errors();
        }
    }

    /**
     * Get Headers of CSV
     * @return array
     */
    public function getHeaderMap()
    {
        return Config('bulk-upload.technicalSpecs');
    }

    /**
     * Get Default Ticket #
     * @return String
     */
    public function getDefaultTicket()
    {
        return "";
    }

    /**
     * Get Status Slug
     * @return string
     */
    public function getStatusSlug()
    {
        return "";
    }

    /**
     * Get Status Name
     * @return string
     */
    public function getStatusName()
    {
        return "";
    }

    /**
     * Get Data for History and Asset
     * @param  array  $inputData
     * @param  int    $count     
     * @return array            
     */
    public function getData(array $inputData, int $count)
    {
        return [];
    }

    /**
     * After bulk upload attach the uploaded file to the ticket as comment
     * @param mixed $ticketid
     * @param mixed $filePath
     * @param mixed $fileName
     * 
     * @return [type]
     */
    public function attachFiletoTicket($ticketid, $filePath, $fileName)
    {
        if (!$ticketid || !$filePath || !$fileName) {
            return false;
        }
        $this->ticketManagementService->attachActionHistorytoTicket($ticketid, 'Bulk technical specs update', Auth::user()->id, $filePath, $fileName);
        return true;
    }

    /**
     * Save Data from the request
     * @param  array  $inputData
     * @param  int    $i
     * @return void
     */
    public function saveData(array $inputData, int $i)
    {
        try {
            if ($inputData['technical_spec_id' . $i]) {
                $techSpec = TechnicalSpecs::with(['makeAndModel'])->where('id', $inputData['technical_spec_id' . $i])->first();
                $techSpecData = [
                    'make_and_model_id' => $inputData['make_and_model_id' . $i] ?: $techSpec->make_and_model_id,
                    'details' => $inputData['new_technical_specs' . $i],
                    'original_value' => $inputData['original_value' . $i] ?: $techSpec->original_value,
                    'new_value' => $inputData['new_value' . $i] ?: $techSpec->new_value,
                    'status' => $inputData['status' . $i] ? ($inputData['status' . $i] == 'Active' ? 1 : 0) : $techSpec->status,
                ];
                $this->createUpdateHistory($inputData, $techSpec, $i);
                TechnicalSpecs::where('id', $inputData['technical_spec_id' . $i])->update($techSpecData);
            } else {

                $techSpecData = [
                    'make_and_model_id' => $inputData['make_and_model_id' . $i],
                    'details' => $inputData['new_technical_specs' . $i],
                    'original_value' => $inputData['original_value' . $i],
                    'new_value' => $inputData['new_value' . $i] ?? 0,
                    'status' => $inputData['status' . $i] == 'Active' ? 1 : 0,
                ];
                $this->createHistory($inputData, $i);
                TechnicalSpecs::Create($techSpecData)->id;
            }
            return true;
        } catch (\Exception) {
            return true;
        }
    }

    /**
     * Creates the hardware update history
     * @param mixed $inputData
     * @param mixed $existingdata
     * @param mixed $i
     * 
     * @return [type]
     */
    private function createUpdateHistory($inputData, $existingdata, $i)
    {
        $description = '';

        if (($inputData['current_technical_specs' . $i] && $inputData['new_technical_specs' . $i]) && ($inputData['new_technical_specs' . $i] != $inputData['current_technical_specs' . $i])) {
            $description .= __('history.FieldsUpdated', [
                'fieldName' => 'Tech Specs',
                'oldValue'    => $inputData['current_technical_specs' . $i],
                'newValue'  => $inputData['new_technical_specs' . $i],
            ]);
        }

        if (($inputData['status' . $i] && $existingdata->status) && ($inputData['status' . $i] != $existingdata->status)) {
            $description .= __('history.FieldsUpdated', [
                'fieldName' => 'Status',
                'oldValue'    => $existingdata->status == 0 ? 'Inactive' : 'Active',
                'newValue'  => $inputData['status' . $i],
            ]);
        }

        if (($inputData['make_and_model_id' . $i] && $existingdata->make_and_model_id) && ($inputData['make_and_model_id' . $i] != $existingdata->make_and_model_id)) {
            $description .= __('history.FieldsUpdated', [
                'fieldName' => 'Hardware Standard',
                'oldValue'    => $existingdata->status == 0 ? 'Inactive' : 'Active',
                'newValue'  => $inputData['status' . $i],
            ]);
        }

        if (($inputData['new_value' . $i] && $existingdata->new_value) && ($inputData['new_value' . $i] != $existingdata->new_value)) {
            $description .= __('history.FieldsUpdated', [
                'fieldName' => 'Savage Value',
                'oldValue' => $existingdata->new_value,
                'newValue' => $inputData['new_value' . $i],
            ]);
        }

        if (($inputData['original_value' . $i] && $existingdata->original_value) && ($inputData['original_value' . $i] != $existingdata->original_value)) {
            $description .= __('history.FieldsUpdated', [
                'fieldName' => 'Savage Value',
                'oldValue' => $existingdata->original_value,
                'newValue' => $inputData['original_value' . $i],
            ]);
        }

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

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

    /**
     * creates new hardware created history
     * @param mixed $inputData
     * @param int $i
     * 
     * @return [type]
     */
    private function createHistory($inputData, $i)
    {
        $makeModel = MakeAndModel::with(['manufacturer', 'assetType'])->where('id', $inputData['make_and_model_id' . $i])->first();
        $description = __('history.TechnicalSpecsCreated', [
            'assetType' => optional($makeModel->assetType)->name,
            'manufacturer' => optional($makeModel->manufacturer)->name,
            'make_model' => $makeModel->name,
            'technical_spec' => $inputData['new_technical_specs' . $i],
            'original_value' => $inputData['original_value' . $i],
        ]);
        $assetHistory = [
            'user_id' => Auth::id(),
            'action' => 'technical_specs_created',
            '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;
    }
}
