<?php

namespace App\Core\Service;


use App\Exceptions\ApiErrorException;
use App\Core\Repository\PropertyConfig\PropertyConfigRepository;
use App\Core\Validator\PropertyConfig\PropertyConfigCreateValidator;
use App\Core\Repository\SiteConfig\SiteConfigRepository;
use App\Core\Service\PropertyFactService;

use App;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Config;
use Exception;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Validator;

class PropertyConfigService
{

    private $propertyConfigRepository;
    private $propertyConfigCreateValidator;
    private $rateKey;
    private $siteConfigRepository;
    private $siteConfigKey;
    private $propertyFactService;


    public function __construct(
        PropertyConfigRepository $propertyConfigRepository,
        SiteConfigRepository $siteConfigRepository,
        PropertyFactService $propertyFactService,
        PropertyConfigCreateValidator $propertyConfigCreateValidator
    ) {

        $this->propertyConfigRepository = $propertyConfigRepository;
        $this->propertyConfigCreateValidator = $propertyConfigCreateValidator;
        $this->siteConfigRepository = $siteConfigRepository;
        $this->propertyFactService = $propertyFactService;
        $this->rateKey = 'profile_rate_value';
        $this->siteConfigKey = 'profile_rate_mapping';
    }

    public function create($param = [])
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];
        try {
            $insertData =
                [
                    "property_id" => fillOnUndefined($param, "property_id"),
                    "config_key" => fillOnUndefined($param, "config_key"),
                    "config_value_json" => fillOnUndefined($param, "config_value_json"),
                    "status" => fillOnUndefined($param, "status", 1),
                    "created_by" => fillOnUndefined($param, "created_by"),
                    "updated_by" => fillOnUndefined($param, "updated_by"),
                    "created_at" => time(),
                    "updated_at" => time(),
                ];


            $validationResult = $this->propertyConfigCreateValidator->validate($insertData);

            if ($validationResult->errors()->first()) {
                $errors = $validationResult->errors()->all();
                throw new ApiErrorException($errors);
            }


            $userCreateResult = $this->propertyConfigRepository->create($insertData);
            if ($userCreateResult['status'] != 'success') {
                throw new Exception('api-unknown_error');
            }
            $userData = $userCreateResult["data"];
            $response = [
                'status' => true,
                'data' => $userData,
            ];
        } catch (ApiErrorException $e) {
            $response['message'] = implode(', ', $e->getMessageArr());
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
        }

        return output($response);
    }

    public function select($param = [], $column = ['*'])
    {

        $response = ['status' => -1, 'message' => '', 'data' => null];

        try {

            $data = $this->propertyConfigRepository->findByCriteria($param, $column);
            $response = [
                'status' => true,
                'data' => $data,
            ];
        } catch (ApiErrorException $e) {
            $response['message'] = $e->getMessage();
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
        }

        return output($response);
    }

    public function update($id, $param = [])
    {

        $response = ['status' => -1, 'message' => '', 'data' => null];
        try {

            $updateResult = $this->propertyConfigRepository->update($id, $param);
            if ($updateResult['status'] != 'success') {
                throw new Exception('api-unknown_error');
            }
            $updateData = $updateResult["data"];
            $response = [
                'status' => true,
                'data' => $updateData,
            ];
        } catch (ApiErrorException $e) {
            $response['message'] = implode(', ', $e->getMessageArr());
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
        }

        return output($response);
    }

    public function updateOrCreate($criteria = [], $saveData = [])
    {


        $response = ['status' => -1, 'message' => '', 'data' => null];

        try {

            $data = $this->propertyConfigRepository->updateOrCreate($criteria, $saveData);
            if ($data['status'] != 'success') {
                throw new Exception('api-unknown_error');
            }
            $response = [
                'status' => true,
                'data' => $data,
            ];
        } catch (ApiErrorException $e) {
            $response['message'] = $e->getMessage();
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
        }

        return output($response);
    }

    public function getPropertyConfig($params)
    {

        $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500];
        try {
            $return = [];
            $configRequest = [
                'criteria' => [
                    ['field' => 'status', 'condition' => '=', 'value' => 1],
                    ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']],
                ],

            ];

            if ($params['config_keys']) {

                $configRequest['whereIn'] = [
                    ["field" => "config_key", "value" => $params['config_keys']]
                ];
            }
            $configResponse = $this->select($configRequest, ['property_id', 'config_key', 'config_value_json']);

            if ($configResponse['status'] != 'success') {
                throw new ApiErrorException(lang('Executive Data Not Loaded'));
            }
            $configCollection = collect($configResponse['data']);

            foreach ($configCollection as $config) {
                $configItem['property_id'] = $config['property_id'];
                $configItem['config_key'] = $config['config_key'];
                $configItem['config_value_json'] = $config['config_value_json'];
                $return[] = $configItem;
            }
            $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => ['property_config' => $return]];
        } catch (ApiErrorException $e) {
            $response['message'] = implode(', ', $e->getMessageArr());
            $response['statusCode'] = 400;
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 500;
        }

        return output($response);
    }

    public function propertyConfigUpdate($params)
    {

        $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500];
        try {
            $return = [];

            $requestKeys = collect($params['config_keys'])->keyBy("config_key")->keys()->toArray();


            $configRequest = [
                'criteria' => [
                    ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']],
                ],
                "whereIn" => [
                    ["field" => "config_key", "value" => $requestKeys]
                ]
            ];

            $configResponse = $this->select($configRequest);

            $configCollection = collect($configResponse['data']);

            foreach ($params['config_keys'] as $config_key) {

                $configKeyCheck = $configCollection->where('config_key', '=', $config_key['config_key'])
                    ->first();

                if ($configKeyCheck) {
                    $updateData = [
                        'config_value_json' => $config_key['config_value_json'],
                        'updated_by' => $params['user_id'],
                        'status' => 1,
                    ];
                    $updateStatus = $this->update($configKeyCheck['id'], $updateData);

                    if ($updateStatus['status'] != 'success') {
                        throw new Exception($updateStatus['message']);
                    }
                } else {
                    $createData = [
                        'property_id' => $params['property_id'],
                        'config_key' => $config_key['config_key'],
                        'config_value_json' => $config_key['config_value_json'],
                        'updated_by' => $params['user_id'],
                        'created_by' => $params['user_id'],
                    ];
                    $createStatus = $this->create($createData);
                    if ($createStatus['status'] != 'success') {
                        throw new Exception($createStatus['message']);
                    }
                }
            }

            $requestParams = [

                'locale' => fillOnUndefined($params, 'locale'),
                'property_id' => fillOnUndefined($params, 'property_id'),
                'config_keys' => $requestKeys

            ];

            $propertyConfig = $this->getPropertyConfig($requestParams);

            if ($propertyConfig['status'] != 'success') {
                throw new ApiErrorException($propertyConfig['message']);
            }

            $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => $propertyConfig['data']];
        } catch (ApiErrorException $e) {
            $response['message'] = implode(', ', $e->getMessageArr());
            $response['statusCode'] = 400;
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 500;
        }

        return output($response);
    }

    public function checkRateForId($params)
    {

        $response = $params;
        $response['property_rate_for'] = $response['property_rate_for'] == 'Property.Fact.SubCategoryFacts' ? 'Property.Fact.SubCategoryFacts' . '.' . $response['sub_category_id'] : $response['property_rate_for'];
        return $response;
    }

    public function rateProperty($rateParams)
    {
        $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500];
        try {

            $rateParams = $this->checkRateForId($rateParams);
            $selectProperty = [
                'criteria' => [
                    ['field' => 'status', 'condition' => '=', 'value' => 1],
                    ['field' => 'property_id', 'condition' => '=', 'value' => $rateParams['property_id']],
                    ['field' => 'config_key', 'condition' => '=', 'value' => $this->rateKey],
                ],
                'firstRow' => 1

            ];
            $propertyRates = $this->select($selectProperty);

            if ($propertyRates['status'] != "success") {
                throw new Exception($propertyRates['message']);
            }

            if ($propertyRates['data'] == null) {
                $configValue[] = $rateParams['property_rate_for'];
                $configValueJson = json_encode($configValue);
                $updateParams = [
                    'property_id' => $rateParams['property_id'],
                    'config_key' => $this->rateKey,
                    'config_value_json' => $configValueJson,
                    'status' => 1,
                    'created_by' => $rateParams['user_id'],
                    'updated_by' => $rateParams['user_id'],
                    'created_at' => time(),
                    'updated_at' => time()
                ];
                $updateStatus = $this->create($updateParams);
                if ($updateStatus['status'] != 'success') {
                    throw new Exception($updateStatus['message']);
                }
            } else {
                $propertyRates = $propertyRates['data'] ? $propertyRates['data'] : [];
                $configValue = json_decode($propertyRates['config_value_json'], 1);
                $configValue = is_array($configValue) ? $configValue : [];
                if (!in_array($rateParams['property_rate_for'], $configValue)) {
                    array_push($configValue, $rateParams['property_rate_for']);
                    $configValueJson = json_encode($configValue);
                    $updateParams = [
                        'config_value_json' => $configValueJson,
                        'updated_by' => $rateParams['user_id'],
                        'updated_at' => time()
                    ];
                    $updateStatus = $this->update($propertyRates['id'], $updateParams);
                    if ($updateStatus['status'] != 'success') {
                        throw new Exception($updateStatus['message']);
                    }
                }
            }
            $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => $configValue];
        } catch (ApiErrorException $e) {
            $response['message'] = implode(', ', $e->getMessageArr());
            $response['statusCode'] = 400;
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 500;
        }

        return output($response);
    }

    public function propertyDashBoard($params)
    {

        $response = ['status' => false, 'message' => '', 'data' => null, 'statusCode' => 500];
        try {

            $return = [];

            $siteConfigRequest = [
                'criteria' => [
                    ['field' => 'status', 'condition' => '=', 'value' => 1],
                    ['field' => 'config_key', 'condition' => '=', 'value' => $this->siteConfigKey],
                ],
                'firstRow' => 1
            ];

            $siteConfig = $this->siteConfigRepository->findByCriteria($siteConfigRequest);

            $siteConfig = $siteConfig ? $siteConfig : [];
            $rateConfig = fillOnUndefined($siteConfig, 'config_value_json', null);
            $rateConfig = json_decode($rateConfig, 1);
            $dashboardSections = is_array($rateConfig) && isset($rateConfig['dashboard_section']) ? $rateConfig['dashboard_section'] : [];


            foreach ($dashboardSections as $key => $value) {
                $return[$key]['title'] = $value['title'];
                $return[$key]['icon'] = $value['icon'];
                $return[$key]['description'] =   $value['description'];
                if (isset($value['menus'])) {
                    $return[$key]['menus'] =   $value['menus'];
                }
            }

            $amenityMenu = $this->propertyFactService->getSubCategoryMenus(['parent_id' => 1, 'sub_category_id' => null]);
            if ($amenityMenu['status'] != 'success') {
                throw new ApiErrorException($amenityMenu['message']);
            }

            $facilityMenu = $this->propertyFactService->getSubCategoryMenus(['parent_id' => 44, 'sub_category_id' => null]);
            if ($facilityMenu['status'] != 'success') {
                throw new ApiErrorException($facilityMenu['message']);
            }


            $return['amenities']['menus'] = $amenityMenu['data']['menu'];
            $return['facility']['menus'] = $facilityMenu['data']['menu'];

            $wizardParams = [
                'menu_array' => $return,
                'property_id' => $params['property_id']
            ];


            $return = $this->checkWizard($wizardParams);
            $response = ['status' => 1, 'statusCode' => 200, 'message' => null, 'data' => ['dashboard' => $return]];
        } catch (ApiErrorException $e) {
            $response['message'] = implode(', ', $e->getMessageArr());
            $response['statusCode'] = 400;
        } catch (Exception $e) {
            $message = $e->getFile() . " " . $e->getLine() . " " . $e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 500;
        }

        return output($response);
    }


    public function checkWizard($params)
    {

        $selectProperty = [
            'criteria' => [
                ['field' => 'status', 'condition' => '=', 'value' => 1],
                ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']],
                ['field' => 'config_key', 'condition' => '=', 'value' => $this->rateKey],
            ],
            'firstRow' => 1
        ];
        $propertyRates = $this->propertyConfigRepository->findByCriteria($selectProperty);
        $propertyRates = $propertyRates ? $propertyRates : [];
        $rates = fillOnUndefined($propertyRates, 'config_value_json', '[]');
        $rates = json_decode($rates, 1);
        $return = [];
        foreach ($params['menu_array'] as $key => $value) {
            $return[$key] = $value;
            $menus = [];
            $completed = 0;
            if (isset($value['menus'])) {
                foreach ($value['menus'] as $menu) {
                    $menu['wizard_completed'] = array_search($menu['alias'], $rates) > -1;
                    $completed = array_search($menu['alias'], $rates) > -1 ? $completed + 1 : $completed;
                    $menus[] = $menu;
                }
                $return[$key]['menus'] = $menus;
                $return[$key]['total_module'] = count($menus);
                $return[$key]['completed_module'] = $completed;
            }
        }
        return $return;
    }
}
