<?php

namespace App\Services;

use Facades\App\Repositories\BulkUpload;
use Facades\App\Services\AssetBulkUpload;
use Illuminate\Support\Facades\Validator;
use App\Models\Asset;
use App\Models\AssetStatus;
use App\Events\BulkUpdates;
use Illuminate\Support\Facades\Auth;
use Carbon\Carbon;

class BulkAttributeUpdate
{
    public function importAssetData($path)
    {
        $count = 1;
        $data = $this->getItems($path);
        $items = $data['csvData'];
        $csvData['error'] = $data['error'];
        $csvData['csvData'] = [];
        if (!empty($items)) {
            foreach ($items as $key => $item) {
                if (!count($item)) continue; //skip empty columns
                $csvData['csvData'][] = $this->generateCSVData($item, $count++);
            }
        }
        return $csvData;
    }

    public function getItems($path)
    {
        if (!file_exists($path)) return false;
        $items = csv_to_array($path);
        if (empty($items)) return false;
        return $items;
    }

    public function generateCSVData($item, $count)
    {
        $headerMap = Config('bulk-upload.attributeUpdateData');
        if (empty($item)) return false;
        $assetData    = [];
        foreach ($headerMap as $dbField => $fileHeader) {
            $result = $this->getRelationalValues($item, $dbField, $fileHeader);
            if ($result !== false) {
                $item[$fileHeader] = $result;
            }

            $assetData[$dbField] = !empty($item[$fileHeader]) ? $item[$fileHeader] : null;
            if ($dbField == "serial_no") {
                if (!empty($item[$fileHeader])) {
                    $asset = Asset::where('serial_no', trim($item[$fileHeader]))->first();
                    if ($asset) {
                        $assetData['asset_id'] = $asset->id;
                    }
                    if (!$asset) {
                        $assetData['asset_id'] = null;
                    }
                }
            }
        }

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

        return compact('assetData');
    }

    public function validateCsvColumns($path, $csvData)
    {
        $headerMap = Config('bulk-upload.attributeUpdateData');
        $headerKeys = array_values($headerMap);

        $csv = array_map("str_getcsv", file($path, FILE_SKIP_EMPTY_LINES));
        $csvKeys = array_shift($csv);

        $result = [];

        if (empty($csvData)) {
            return 'Please make sure the file contains data';
        }
        $messages = $this->checkFileDifference($csvKeys, $headerKeys);
        return $messages;
    }

    public function validateFields($csvData)
    {
        $count = 2;
        foreach ($csvData as $data) {
            $errors[] = $this->csvValidator($data['assetData'], $count++);
        }
        return $errors;
    }

    public function csvValidator($data, $count)
    {
        $validator = Validator::make(
            $data,
            [
                'serial_no'          => 'required|exists:assets,serial_no',
                'asset_tag' => 'nullable|distinct|unique:assets,asset_tag',
                'make_and_model_id' => 'nullable|exists:make_and_models,id',
                'technical_spec_id' => 'nullable|exists:technical_specs,id',
                'asset_type_id' => 'nullable|exists:asset_types,id',
                'carrier_id'    => 'nullable|exists:carriers,id',
                'legalhold'     => 'nullable|exists:users,legalhold,0',
            ],
            $messages = [
                'serial_no.required'          => 'Line no ' . $count . ' : The serial # is required.',
                'serial_no.exists'            => 'Line no ' . $count . ' : The serial # does not exists.',
                'asset_tag.distinct' => 'Line no ' . $count . ' : The asset tag # has already been taken.',
                'asset_tag.unique' => 'Line no ' . $count . ' : The asset tag # has already been taken.',
                'make_and_model_id.exists'    => 'Line no ' . $count . ' : The hardware standard does not exist.',
                'technical_spec_id.exists'    => 'Line no ' . $count . ' : The technical specs does not exist.',
                'asset_type_id.exists'    => 'Line no ' . $count . ' : The asset type does not exist.',
                'carrier_id.exists'    => 'Line no ' . $count . ' : The carrier does not exist.',
                'legalhold'  => 'Line no ' . $count . ' : Assets on legal hold employees can not be edited.',
            ]
        );

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

    public function checkFileDifference($csvKeys, $headerKeys)
    {
        if (count($headerKeys) >= count($csvKeys)) {
            $result = array_diff($headerKeys, $csvKeys);
            $messageString = 'Please make sure the column names are spelled correctly. Columns missing - ';
        } else {
            $result = array_diff($csvKeys, $headerKeys);
            $messageString = 'Uploaded file is not match with template file. Extra columns - ';
        }
        $messages = '';

        if (!empty($result)) {
            foreach ($result as $key => $value) {
                $messageString .= $value . ', ';
            }
            $messages = rtrim($messageString, ", ");
        }
        return $messages;
    }

    public function importAssetSpecialData($path)
    {
        $data = $this->getItems($path);
        $items = $data['csvData'];
        $errorData = [];
        if (!empty($items)) {

            foreach ($items as $key => $item) {

                if (!count($item)) continue; //skip empty columns
                $csvData = $this->generateSpecialCSVData($item);
                $assetData = $csvData['assetData'];
                if ($csvData['errorData']) {
                    $errorData[] = $csvData['errorData'];
                }
                if (isset($assetData['id'])) {
                    $asset = Asset::find($assetData['id']);
                    if ($asset) {
                        $description = "Updated attributes of Asset <a href='route('assets.show', $asset->id)'>$asset->asset_tag</a>";
                        foreach (Config('bulk-upload.attributeUpdateData') as $key => $value) {

                            if ($assetData[$key]) {
                                if ($key != "serial_no") {
                                    $description = $description . ' ' . $value . ' Updated From ' . $asset->$key . ' to ' . $assetData[$key] . ', ';
                                }
                                if ($key == "created_at") {
                                    $asset->$key = convert_to_db_datetime($assetData[$key]);
                                } else {
                                    $asset->$key = $assetData[$key];
                                }
                            }
                            if (!$assetData['created_at']) {
                                $asset->$key = Carbon::now()->format('Y-m-d H:i:s');
                            }
                        }
                        $description =  rtrim($description, ', ');
                        $assetHistory = [
                            'user_id' => Auth::id(),
                            'asset_id' => $asset->id,
                            'action' => 'assetAttributes_changed',
                            'description' => $description,
                        ];
                        event(new BulkUpdates($assetHistory));
                        $asset->save();
                    }
                }
            }
        }
        return $errorData;
    }

    public function generateSpecialCSVData($item)
    {
        $headerMap = Config('bulk-upload.attributeUpdateData');
        if (empty($item)) return false;
        $assetData    = [];
        $errorData    = [];
        foreach ($headerMap as $dbField => $fileHeader) {
            $result = $this->getRelationalValues($item, $dbField, $fileHeader);
            if ($result !== false) {
                $item[$fileHeader] = $result;
            }

            $assetData[$dbField] = !empty($item[$fileHeader]) ? $item[$fileHeader] : null;
            if ($dbField == "serial_no") {
                if (!empty($item[$fileHeader])) {
                    $asset = Asset::where('serial_no', trim($item[$fileHeader]))->first();
                    if ($asset) {
                        $assetData['id'] = $asset->id;
                    }
                    if (!$asset) {
                        $errorData[] = 'Asset with serial # ' . $item[$fileHeader] . ' do not exist';
                    }
                }
            }
        }

        return compact('assetData', 'errorData');
    }

    public function getRelationalValues($item, $dbField, $fileHeader)
    {
        if ($dbField == "asset_type_id") {
            return BulkUpload::getAssetTypeId($item, $dbField, $fileHeader);
        }

        if ($dbField == "make_and_model_id") {
            return BulkUpload::getAttributeMakeModelId($item, $dbField, $fileHeader);
        }

        if ($dbField == "technical_spec_id") {
            return BulkUpload::getAttributeTechnicalSpecId($item, $dbField, $fileHeader);
        }

        if ($dbField == "carrier_id") {
            return BulkUpload::getCarrierId($item, $dbField, $fileHeader);
        }

        return false;
    }
}
