<?php

namespace App\Services;

use Facades\App\Repositories\BulkUpload;
use Illuminate\Support\Facades\Validator;
use App\Models\Asset;
use App\Models\AssetStatus;
use Illuminate\Support\Facades\Auth;
use App\Models\AssetHistory;
use Facades\App\Services\AssetHistory as RepoAssetHistory;
use App\Events\BulkUpdates;

class BulkHold
{
    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.holdAssetData');
        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 getRelationalValues($item, $dbField, $fileHeader)
    {
        if ($dbField == "asset_status_id") {
            return BulkUpload::getStatusId($item, $dbField, $fileHeader);
        }
        if ($dbField == "location_id") {
            return BulkUpload::getLocationId($item, $dbField, $fileHeader);
        }
        if ($dbField == "user_id") {
            return BulkUpload::getUserId($item, $dbField, $fileHeader);
        }
        return false;
    }

    public function validateCsvColumns($path, $csvData)
    {
        $headerMap = Config('bulk-upload.holdAssetData');
        $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',
                'location_id'        => 'required|exists:locations,id',
                'user_id'            => 'required|exists:users,id',
                'asset_status_id'    => 'required',
            ],
            $messages = [
                'serial_no.required'          => 'Line no ' . $count . ' : The serial # is required.',
                'serial_no.exists'            => 'Line no ' . $count . ' : The serial # does not exists.',
                'location_id.required'        => 'Line no ' . $count . ' : The location is required.',
                'location_id.exists'          => 'Line no ' . $count . ' : The location does not exists.',
                'user_id.required'            => 'Line no ' . $count . ' : The user is required.',
                'user_id.exists'              => 'Line no ' . $count . ' : The user does not exists.',
                'asset_status_id.required'    => 'Line no ' . $count . ' : The status is required.',
            ]
        );

        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::with('assetStatus', 'childrenAsset')->where('id', $assetData['id'])->first();
                    if ($asset) {

                        $comments = null;
                        $data['user_id'] = $assetData['user_id'];
                        $data['location_id'] = $assetData['location_id'];
                        $data['loaner_retention_date'] = $assetData['loaner_retention_date'];
                        $status = AssetStatus::find($assetData['asset_status_id'])->name;
                        $description = RepoAssetHistory::getStatusDescription($status, $data, $asset, $comments);
                        $assetHistory = [
                            'user_id' => Auth::id(),
                            'asset_id' => $asset->id,
                            'action' => 'status_updated',
                            'comments' => $comments,
                            'old_value' => optional($asset->assetStatus)->name,
                            'new_value' => $status,
                            'description' => $description,
                        ];

                        $assetHistory = $this->getHistoryData($assetHistory, $data, $asset);
                        event(new BulkUpdates($assetHistory));

                        $asset->update($assetData);
                        if ($asset->has('childrenAsset')) {
                            foreach ($asset->childrenAsset as $assetChild) {
                                $assetChild->update([
                                    'user_id' => $assetData['user_id'],
                                    'location_id' => $assetData['location_id'],
                                    'asset_status_id' => $assetData['asset_status_id'],
                                ]);
                            }
                        }
                    }
                }
            }
        }
        return $errorData;
    }

    public function generateSpecialCSVData($item)
    {
        $headerMap = Config('bulk-upload.holdAssetData');
        if (empty($item)) return false;
        $assetData    = [];
        $errorData    = [];
        foreach ($headerMap as $dbField => $fileHeader) {
            $result = $this->getRelationalValues($item, $dbField, $fileHeader);
            if ($result !== false) {
                $item[$fileHeader] = $result;
            }
            if ($result == false) {
                if ($dbField == "location_id") {
                    $errorData[] = 'Location with room name ' . $item[$fileHeader] . ' does not exist';
                }
                if ($dbField == "user_id") {
                    $errorData[] = 'USer with email ' . $item[$fileHeader] . ' does not exist';
                }
            }
            $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;
                        $assetData['loaner_retention_date'] = null;
                        $assetData['wipe_confirmation'] = null;
                        $assetData['lost_date'] = null;
                        $assetData['end_of_life_date'] = null;
                    }
                    if (!$asset) {
                        $errorData[] = 'Asset with serial # ' . $item[$fileHeader] . ' do not exist';
                    }
                }
            }
        }

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

    public function getHistoryData($assetHistory, $assetData, $asset)
    {
        $keyArray = ['loaner_return_date', 'location_id', 'user_id', 'loaner_retention_date', 'asset_status_id'];
        foreach ($keyArray as $key) {
            if (array_key_exists($key, $assetData)) {
                $assetHistory['new_' . $key] = $assetData[$key];
                $assetHistory['old_' . $key] = $asset->$key;
            }
        }
        if (array_key_exists('wipe_confirmation', $assetData)) {
            $assetHistory['wipe_confirmation'] = $assetData['wipe_confirmation'];
        }
        return $assetHistory;
    }
}
