<?php


namespace App\Core\Service\PropertyPhotoService;

use App\Core\Repository\PropertyPhoto\PropertyPhotoRepository;
use App\Core\Repository\PhotoGoogleLabel\PhotoGoogleLabelRepository ;
use App\Core\Service\Google\GoogleVisionLabelService;
use App\Exceptions\ApiErrorException;
use App\Core\Service\PropertyPlaceService;
use Exception;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Config;
use Intervention\Image\Facades\Image;
use App\Core\Service\PropertyRoomPhotoMappingService;
use App\Core\Service\PropertyRoomService ;
use App\Core\Service\OfferPhotoMappingService;
use App\Core\Service\PropertyWebPhotoMappingService;
use App\Core\Validator\Property\PropertyPhotoValidator;
use App\Core\Repository\PropertyPlacePhotoMapping\PropertyPlacePhotoMappingRepository;

use App;



class PropertyPhotoService
{
    public $propertyPhotoRepository;
    public $photoGoogleLabelRepository;
    private $googleVisionLabelService;
    private $propertyRoomPhotoMappingService;
    private $propertyRoomService;
    private $offerPhotoMappingService;
    private $propertyWebPhotoMappingService;
    private $propertyPhotoValidator;
    private $propertyPlaceService;
    private $propertyPlacePhotoMappingRepository;


    public function __construct(

        PropertyPhotoRepository $propertyPhotoRepository,
        PhotoGoogleLabelRepository $photoGoogleLabelRepository,
        GoogleVisionLabelService $googleVisionLabelService,
        PropertyRoomPhotoMappingService $propertyRoomPhotoMappingService,
        OfferPhotoMappingService $offerPhotoMappingService,
        PropertyRoomService $propertyRoomService,
        PropertyPhotoValidator $propertyPhotoValidator,
        PropertyPlaceService $propertyPlaceService,
        PropertyPlacePhotoMappingRepository $propertyPlacePhotoMappingRepository,
        PropertyWebPhotoMappingService $propertyWebPhotoMappingService
    )
    {
        $this->propertyPhotoRepository = $propertyPhotoRepository;
        $this->photoGoogleLabelRepository = $photoGoogleLabelRepository ;
        $this->googleVisionLabelService = $googleVisionLabelService;
        $this->propertyRoomPhotoMappingService = $propertyRoomPhotoMappingService;
        $this->propertyRoomService = $propertyRoomService ;
        $this->offerPhotoMappingService = $offerPhotoMappingService ;
        $this->propertyWebPhotoMappingService = $propertyWebPhotoMappingService;
        $this->propertyPhotoValidator = $propertyPhotoValidator ;
        $this->propertyPlaceService = $propertyPlaceService ;
        $this->propertyPlacePhotoMappingRepository = $propertyPlacePhotoMappingRepository ;
    }

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

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

        try {

            $data = $this->propertyPhotoRepository->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 updateWhere($criteria, $param = [])
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];
        try {

            $updateResult = $this->propertyPhotoRepository->updateWhere($criteria, $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 getPropertyPhotos($params)
    {
        $response = ['status' => false, 'statusCode' => 500 ,'message' => '', 'data' => null];
        try
        {
            $propertyId = $params['property_id'];

            $getPropertyPhotoCriteria =
                [
                    'criteria' =>
                        [
                            ['field' => 'property_id', 'condition' => '=', 'value' => $propertyId],
                            ['field' => 'status', 'condition' => '=', 'value' => 1],
                        ],
                    'orderBy' =>
                        [
                            ["field" => "photo_order", "value" => "ASC"]
                        ],
                ];

            $customIds = fillOnUndefined($params, 'custom', []);
            if(!empty($customIds)) {
                $getPropertyPhotoCriteria['whereIn'] = [
                    ["field" => "id", "value" => $customIds]
                ];
            }

            $getPropertyPhotos = $this->propertyPhotoRepository->findByCriteria($getPropertyPhotoCriteria);
            $getPropertyPhotos = $getPropertyPhotos ? $getPropertyPhotos : [];


            $filteredList = [];
            foreach ($getPropertyPhotos as $key => $getPropertyPhoto)
            {
                $photoUrlFilePath = Config::get('app.fileSystemDriver') . "/property-photos/{$getPropertyPhoto['property_id']}" . "/{$getPropertyPhoto['photo_name']}_1024x768.{$getPropertyPhoto['file_ext']}";
                $photoUrlThumbFilePath = Config::get('app.fileSystemDriver') . "/property-photos/{$getPropertyPhoto['property_id']}" . "/{$getPropertyPhoto['photo_name']}_200x200.{$getPropertyPhoto['file_ext']}";

                if (File::exists($photoUrlFilePath)) {
                    $photoUrlFilePath = Config::get('app.imageUrl') . "/property-photos/{$getPropertyPhoto['property_id']}" . "/{$getPropertyPhoto['photo_name']}_1024x768.{$getPropertyPhoto['file_ext']}";
                }else {
                    $photoUrlFilePath = Config::get('app.imageUrl') . "/property-photos/{$getPropertyPhoto['property_id']}" . "/{$getPropertyPhoto['photo_name']}_medium.{$getPropertyPhoto['file_ext']}";
                }

                if (File::exists($photoUrlThumbFilePath)) {
                    $photoUrlThumbFilePath = Config::get('app.imageUrl') . "/property-photos/{$getPropertyPhoto['property_id']}" . "/{$getPropertyPhoto['photo_name']}_200x200.{$getPropertyPhoto['file_ext']}";
                }else{
                    $photoUrlThumbFilePath = Config::get('app.imageUrl') . "/property-photos/{$getPropertyPhoto['property_id']}" . "/{$getPropertyPhoto['photo_name']}_thumbnail.{$getPropertyPhoto['file_ext']}";
                }

                $filteredList[] =
                    [
                        'id'                         => $getPropertyPhoto['id'],
                        'property_id'                => $getPropertyPhoto['property_id'],
                        'property_photo_category_id' => $getPropertyPhoto['property_photo_category_id'],
                        'photo_url'                  => $photoUrlFilePath,
                        'photo_url_thump'            => $photoUrlThumbFilePath,
                        "photo_name"                 => $getPropertyPhoto["photo_name"],
                        "photo_rank"                 => $getPropertyPhoto["photo_rank"],
                        "file_size"                  => $getPropertyPhoto["file_size"],
                        "file_ext"                   => $getPropertyPhoto["file_ext"],
                        "photo_resolution"           => $getPropertyPhoto["photo_resolution"],
                        "photo_order"                => $getPropertyPhoto["photo_order"],
                        "is_default"                 => $getPropertyPhoto["is_default"],
                        "is_compatible_with_myweb_slider" => $getPropertyPhoto["is_compatible_with_myweb_slider"],
                        "is_temp"                    => $getPropertyPhoto["is_temp"],
                        "status"                     => $getPropertyPhoto["status"],
                    ];
            }

            $response = ['status' => 1, 'statusCode' => 200 ,'message' => '', 'data' => $filteredList];

        }catch (ApiErrorException $e){
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 204;
        }catch (Exception $e){
            $message = $e->getFile().' '.$e->getLine().' '.$e->getMessage();
            Log::error($message);
        }
        return output($response);
    }

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

            $collectLabels = collect($params);

            $descriptions = $collectLabels->keyBy('description')->keys()->toArray();
            $labelCriteria = [
                'whereIn' => [
                    ["field" => "label", "value" => $descriptions]
                ],
                'with' => ['photoCategoryLabelMapping.photoCategory']
            ];
            $categoryList = $this->photoGoogleLabelRepository->findByCriteria($labelCriteria);

            $dbLabels = [];
            $ratedCategories = [];
            foreach ($categoryList as $category){
                $label = $category["label"];
                $categoryId = $category["photo_category_label_mapping"]["photo_category"]["id"];
                $categoryName = $category["photo_category_label_mapping"]["photo_category"]["category_name"];

                //$dbLabels[$label][$categoryId]["category_name"] = $categoryName;

                $rate = $collectLabels->where('description', '=', $label)->first();

                $ratedCategories[$categoryId]["category_id"] = $categoryId;
                $ratedCategories[$categoryId]["category_name"] = $categoryName;
                if(!isset($ratedCategories[$categoryId]["rate"])){
                    $ratedCategories[$categoryId]["rate"] = 0;
                }
                else{
                    $ratedCategories[$categoryId]["rate"] += $rate['score'];
                }

            }

            $winner = collect($ratedCategories)->sortByDesc('rate')->first();

            $response = ['status' => 1, 'statusCode' => 200 ,'message' => '', 'data' => $winner];

        }catch (ApiErrorException $e){
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 204;
        }catch (Exception $e){
            $message = $e->getFile().' '.$e->getLine().' '.$e->getMessage();
            Log::error($message);
        }
        return output($response);
    }

    public function insertPropertyPhoto($param)
    {
        return $this->propertyPhotoRepository->create($param);
    }

    public function setPhotoOrder($params){
        $response = ['status' => false, 'statusCode' => 500 ,'message' => '', 'data' => null];
        try
        {
            foreach ($params['set_photo_order'] as $orderList){
                $updateData = [
                    'photo_order' => $orderList['photo_order'],
                    'updated_at' => time() ,
                ];
                $updateCriteria = [
                    'criteria' => [
                        ['field' => 'id' , 'condition' => '=', 'value' => $orderList['photo_id'] ],
                        ['field' => 'property_id' , 'condition' => '=', 'value' => $params['property_id'] ],
                    ]
                ];
                $updateStatus = $this->updateWhere($updateCriteria, $updateData);
                if($updateStatus['status'] != 'success'){
                    throw new Exception($updateStatus['message']);
                }
                $response = ['status' => 1, 'statusCode' => 200 ,'message' => '', 'data' => []];
            }
        }catch (ApiErrorException $e){
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 204;
        }catch (Exception $e){
            $message = $e->getFile().' '.$e->getLine().' '.$e->getMessage();
            Log::error($message);
        }
        return output($response);


    }

    public function setPhotoCategory($params){
        $response = ['status' => false, 'statusCode' => 500 ,'message' => '', 'data' => null];
        try
        {
            foreach ($params['set_photo_category'] as $photoList){
                $updateData = [
                    'property_photo_category_id' => $photoList['photo_category_id'],
                    'updated_at' => time() ,
                ];
                $updateCriteria = [
                    'criteria' => [
                        ['field' => 'id' , 'condition' => '=', 'value' => $photoList['photo_id'] ],
                        ['field' => 'property_id' , 'condition' => '=', 'value' => $params['property_id'] ],
                    ]
                ];

                $updateStatus = $this->updateWhere($updateCriteria, $updateData);

                if($updateStatus['status'] != 'success'){
                    throw new ApiErrorException(lang('User data is not updated.'));
                }
            }
            $response = ['status' => 1, 'statusCode' => 200 ,'message' => '', 'data' => []];
        }catch (ApiErrorException $e){
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 204;
        }catch (Exception $e){
            $message = $e->getFile().' '.$e->getLine().' '.$e->getMessage();
            Log::error($message);
        }
        return output($response);


    }

    public function update($id, $param = [])
    {
        $response = ['status' => -1, 'message' => '', 'data' => null];
        try {

            $updateResult = $this->propertyPhotoRepository->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);
    }

    // todo: query performance should be corrected
    public function setDefaultPhoto($params)
    {
        $response = ['status' => false, 'statusCode' => 500 ,'message' => '', 'data' => null];
        try
        {

            $photo_id    = $params['photo_id'];
            $propertyId  = $params['property_id'];

            $requestDataCriteria =
                [
                    'criteria' =>
                        [
                            ['field' => 'property_id', 'condition' => '=', 'value' => $propertyId],
                            ['field' => 'id', 'condition' => '=', 'value' => $photo_id],
                        ],
                ];

            $requestDataCheck = $this->propertyPhotoRepository->findByCriteria($requestDataCriteria,['id']);

            if (empty($requestDataCheck)) {
                throw new ApiErrorException(lang('PropertyPhoto data not found'));
            }

            $propertyPhotoCriteria =
                [
                    'criteria' =>
                        [
                            ['field' => 'property_id', 'condition' => '=', 'value' => $propertyId],
                            ['field' => 'is_default', 'condition' => '=', 'value' => 1]
                        ],
                ];

            $getPropertyPhotoData = $this->propertyPhotoRepository->findByCriteria($propertyPhotoCriteria,['id','is_default']);

            if (!empty($getPropertyPhotoData)) {
                foreach ($getPropertyPhotoData as $photoData ) {
                    $updatedPhotoisDefault = $this->update($photoData['id'],['is_default' => 0]);
                }

                if ($updatedPhotoisDefault['status'] == false) {
                    throw new ApiErrorException(lang('PropertyPhoto "is_default fields" can not updated'));
                }
            }

            $PhotoCriteria =
                [
                    'criteria' =>
                        [
                            ['field' => 'property_id', 'condition' => '=', 'value' => $propertyId],
                            ['field' => 'id', 'condition' => '=', 'value' => $photo_id],
                            ['field' => 'is_default', 'condition' => '=', 'value' => 0],
                        ],
                ];

            $getPhotoData = $this->propertyPhotoRepository->findByCriteria($PhotoCriteria);

            if (!empty($getPhotoData)) {
                $setPropertPhotoDefault = $this->update($photo_id,['is_default' => 1]);
            }

            if ($setPropertPhotoDefault['status'] == false) {
                throw new ApiErrorException(lang('PropertyPhoto "is_default" can not updated'));
            }

            $response = ['status' => 1, 'statusCode' => 200 ,'message' => '', 'data' => ''];

        }catch (ApiErrorException $e){
            $response['message'] = $e->getMessage();

        }catch (Exception $e){
            $message = $e->getFile().' '.$e->getLine().' '.$e->getMessage();
            $response['message'] = $e->getMessage();
            Log::error($message);
        }
        return output($response);
    }

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

        try {
            $photos = $params['photos'];
            $photoData = [];

            foreach ( $photos as $photo ) {
                if ( !is_null($photo['photo_id']) ) {
                    if ( $photo['is_temp'] == 0 ) {
                        $photoData['publish'][] = [$photo['photo_id'] ];
                    } else{
                        $photoData['unPublish'][] = [$photo['photo_id']];
                    }
                }
            }

            if (Arr::has($photoData,'publish')) {
                $photoPublishCriteria = [
                    'criteria' => [
                        ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']],
                    ],
                    'whereIn' => [
                        ['field' => 'id', 'condition' => '=', 'value' => $photoData['publish']],
                    ]
                ];

                $propertyPhotoPublishData = $this->propertyPhotoRepository->findByCriteria($photoPublishCriteria, ['id', 'is_temp']);

                if ( empty($propertyPhotoPublishData) ) {
                    throw new ApiErrorException(lang('photo is_temp data not loaded'));
                }

                foreach ( $propertyPhotoPublishData as $publishData ) {
                    $updatePhotoPublishData = $this->update($publishData['id'], ['is_temp' => 0]);
                }
                if ( $updatePhotoPublishData[ 'status' ] == false ) {
                    throw new ApiErrorException(lang('PropertyPhoto can not published'));
                }
            }

            if (Arr::has($photoData,'unPublish')) {
                $photoUnPublishCriteria = [
                    'criteria' => [
                        [ 'field' => 'property_id', 'condition' => '=', 'value' => $params[ 'property_id' ] ],
                    ],
                    'whereIn' => [
                        [ 'field' => 'id', 'condition' => '=', 'value' => $photoData[ 'unPublish' ] ],
                    ]
                ];

                $propertyPhotoUnPublishData = $this->propertyPhotoRepository->findByCriteria($photoUnPublishCriteria, [ 'id', 'is_temp' ]);

                foreach ( $propertyPhotoUnPublishData as $unPublishData ) {
                    $updatePhotoUnPublishData = $this->update($unPublishData[ 'id' ], [ 'is_temp' => 1 ]);
                }

                if ( $updatePhotoUnPublishData[ 'status' ] == false ) {
                    throw new ApiErrorException(lang('PropertyPhoto can not unpublished'));
                }
            }

            $response = [ 'status' => 1, 'statusCode' => 200, 'message' => '', 'data' => '' ];

        } catch ( ApiErrorException $e ) {
            $response[ 'message' ] = $e->getMessage();
            $response[ 'statusCode' ] = 404;
        } catch ( Exception $e ) {
            $message = $e->getFile() . ' ' . $e->getLine() . ' ' . $e->getMessage();
            $response[ 'message' ] = $e->getMessage();
            Log::error($message);
        }
        return output($response);
    }

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

        try {
            DB::beginTransaction();

            $photos = $params['photos'];

            if (empty($photos)) {
                throw new ApiErrorException(lang('property photos not found'));
            }

            $photoDeleteCriteria = [
                'criteria' => [
                    ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']],
                    ['field' => 'status', 'condition' => '=', 'value' => 1],
                ],
                'whereIn' => [
                    ['field' => 'id', 'condition' => '=', 'value' => $photos],
                ]
            ];

            $propertyPhotoDeleteData = $this->propertyPhotoRepository->findByCriteria($photoDeleteCriteria);

            if (empty($propertyPhotoDeleteData)) {
                throw new ApiErrorException(lang('property photos delete data not loaded'));
            }

            $propertyPhotoDeleteData = $propertyPhotoDeleteData ? $propertyPhotoDeleteData : [] ;
            $defaultPhotoDeleted = false ;
            foreach ( $propertyPhotoDeleteData as $deleteData ) {

                $destroyCriteria = [
                    'photo_id' => $deleteData['id'],
                    'property_id' => $params['property_id']
                ];
                $roomPhotoDelete = $this->propertyRoomPhotoMappingService->destroy($destroyCriteria);
                if ($roomPhotoDelete['status'] == false) {
                    throw new ApiErrorException($roomPhotoDelete['message']);
                }

                $offerPhotoDelete = $this->offerPhotoMappingService->destroy($destroyCriteria);
                if ($offerPhotoDelete['status'] == false) {
                    throw new ApiErrorException($offerPhotoDelete['message']);
                }

                $webPhotoDelete = $this->propertyWebPhotoMappingService->destroy($destroyCriteria);
                if ($webPhotoDelete['status'] == false) {
                    throw new Exception('api-unknown_error');
                }


                $placePhotoDelete = $this->propertyPlaceService->destroyPhotoMapping($destroyCriteria);
                if ($placePhotoDelete['status'] == false) {
                    throw new Exception('api-unknown_error');
                }


                if($deleteData['id']){
                    $propertyPhotoDelete = $this->propertyPhotoRepository->destroy([$deleteData['id']]);
                    if ($propertyPhotoDelete['status'] == false) {
                        throw new Exception('api-unknown_error');
                    }
                }

                if($deleteData['is_default']){
                    $defaultPhotoDeleted = true ;
                }

                $photoUrlThumbFilePath = Config::get('app.fileSystemDriver') . '/property-photos/' . $params['property_id'] . '/'.$deleteData['photo_name'].'_200x200.'.$deleteData['file_ext'];

                if (File::exists($photoUrlThumbFilePath)) {
                    $filePath = Config::get('app.fileSystemDriver') . '/property-photos/' . $params['property_id'] . '/'.$deleteData['photo_name'].'_200x200.' .$deleteData['file_ext'];
                }else{
                    $filePath = Config::get('app.fileSystemDriver') . '/property-photos/' . $params['property_id'] . '/'.$deleteData['photo_name']. '_thumbnail.'.$deleteData['file_ext'];
                }

                //delete thumbnail image
               // $filePath = Config::get('app.fileSystemDriver') . '/property-photos/' . $params['property_id'] . '/'.$deleteData['photo_name'].'_200x200.'.$deleteData['file_ext'];
                if (File::exists($filePath)) {
                    if(!File::delete($filePath)){
                        Log::alert($filePath . ' not deleted');
                    }
                }

                $photoUrlFilePath = Config::get('app.fileSystemDriver') . '/property-photos/' . $params['property_id'] . '/'.$deleteData['photo_name'].'_1024x768.'.$deleteData['file_ext'];

                if (File::exists($photoUrlFilePath)) {
                    $filePath = Config::get('app.fileSystemDriver') . '/property-photos/' . $params['property_id'] . '/'.$deleteData['photo_name']. '_1024x768.' .$deleteData['file_ext'];
                }else {
                    $filePath = Config::get('app.fileSystemDriver') . '/property-photos/' . $params['property_id'] . '/'.$deleteData['photo_name']. '_medium.'.$deleteData['file_ext'];
                }


                //delete large image
               // $filePath = Config::get('app.fileSystemDriver') . '/property-photos/' . $params['property_id'] . '/'.$deleteData['photo_name'].'_1024x768.'.$deleteData['file_ext'];
                if (File::exists($filePath)) {
                    if(!File::delete($filePath)){
                        Log::alert($filePath . ' not deleted');
                    }
                }

                //delete original image
                $filePath = Config::get('app.fileSystemDriver') . '/property-photos/' . $params['property_id'] . '/'.$deleteData['photo_name'].'.'.$deleteData['file_ext'];
                if (File::exists($filePath)) {
                    if(!File::delete($filePath)){
                        Log::alert($filePath . ' not deleted');
                    }
                }


            }

            if($defaultPhotoDeleted){
                $photoCriteria = [
                    'criteria' => [
                        ['field' => 'property_id', 'condition' => '=', 'value' => $params['property_id']],
                        ['field' => 'status', 'condition' => '=', 'value' => 1],
                    ],
                    'firstRow' => 1
                ];

                $propertyPhotoData = $this->propertyPhotoRepository->findByCriteria($photoCriteria, ['id']);
                if($propertyPhotoData){
                    $data = $this->propertyPhotoRepository->update($propertyPhotoData['id'], ['is_default' => 1]);
                    if ($data['status'] != 'success') {
                        throw new Exception('api-unknown_error');
                    }
                }
            }

            $response = [ 'status' => 1, 'statusCode' => 200, 'message' => '', 'data' => '' ];
            DB::commit();

        } catch ( ApiErrorException $e ) {
            $response[ 'message' ] = $e->getMessage();
            DB::rollBack();

        } catch ( Exception $e ) {
            $message = $e->getFile() . ' ' . $e->getLine() . ' ' . $e->getMessage();
            $response[ 'message' ] = $e->getMessage();
            DB::rollBack();
            Log::error($message);
        }
        return output($response);
    }

    public function propertyPhotoUploadFilter($param)
    {
        $response = ['status' => false, 'statusCode' => 500, 'message' => '', 'data' => null];
        try
        {
            $propertyId = fillOnUndefined($param, 'property_id');
            $uploadedPhoto = $this->uploadPhoto($param);
            if($uploadedPhoto['status'] != 'success'){

                throw new ApiErrorException($uploadedPhoto['message']) ;
            }
            $uploadedPhoto = $uploadedPhoto['data'] ;


            $defaultPhotoCriteria = [
                'criteria' => [
                    ['field' => 'property_id', 'condition' => '=', 'value' => $propertyId],
                    ['field' => 'status', 'condition' => '=', 'value' => 1],
                    ['field' => 'is_default', 'condition' => '=', 'value' => 1],
                ],
                'firstRow' => 1
            ];

            $propertyPhotoData = $this->propertyPhotoRepository->findByCriteria($defaultPhotoCriteria, ['id']);

            $insertPropertyPhoto =
                [
                    'property_id'      => $propertyId,
                    'property_photo_category_id' => 1,
                    'photo_path'       => $uploadedPhoto['photo_path'],
                    'photo_name'       => $uploadedPhoto['photo_name'],
                    'file_size'        => $uploadedPhoto['file_size'],
                    'file_ext'         => $uploadedPhoto['file_ext'],
                    'photo_resolution' => $uploadedPhoto['file_resolution'],
                    'is_default' => $propertyPhotoData ? 0 : 1,
                    'is_compatible_with_myweb_slider' => $uploadedPhoto['is_compatible_with_myweb_slider'],
                    'created_by'       => 1,
                    'updated_by'       => 1,
                    'created_at'       => time(),
                    'updated_at'       => time()
                ];

            $response = $this->insertPropertyPhoto($insertPropertyPhoto);
            $photoId = $response['data']['id'];

            $getPhotoCategory['category_id'] = 1;
            $getPhotoCategory['category_name'] = 'Property';

            // Set Photo Order....
            $selectLastPhotoCriteria = [
                'criteria' => [
                    ['field' => 'property_id', 'condition' => '=', 'value' => $propertyId]
                ],
                'orderBy' => [
                    ['field' => 'photo_order', 'value' => 'DESC']
                ],
                'firstRow' => true
            ];
            $selectLastPhoto = $this->select($selectLastPhotoCriteria);
            $selectLastPhoto = $selectLastPhoto['data'];
            $lastOrder = fillOnUndefined($selectLastPhoto, 'photo_order');
            $lastOrder += 1;

            $updatePhotoValues = [
                'property_photo_category_id' => $getPhotoCategory['category_id'],
                'photo_order' => $lastOrder,
            ];
            $updatePhoto = $this->update($photoId , $updatePhotoValues) ; // update
            $updatePhoto = $updatePhoto["data"];

            $photoUrlFilePath = Config::get('app.fileSystemDriver') . "/property-photos/{$updatePhoto['property_id']}" . "/{$updatePhoto['photo_name']}_1024x768.{$updatePhoto['file_ext']}";
            $photoUrlThumbFilePath = Config::get('app.fileSystemDriver') . "/property-photos/{$updatePhoto['property_id']}" . "/{$updatePhoto['photo_name']}_200x200.{$updatePhoto['file_ext']}";

            if (File::exists($photoUrlFilePath)) {
                $photoUrlFilePath = Config::get('app.imageUrl') . "/property-photos/{$updatePhoto['property_id']}" . "/{$updatePhoto['photo_name']}_1024x768.{$updatePhoto['file_ext']}";
            }else {
                $photoUrlFilePath = Config::get('app.imageUrl') . "/property-photos/{$updatePhoto['property_id']}" . "/{$updatePhoto['photo_name']}_medium.{$updatePhoto['file_ext']}";
            }

            if (File::exists($photoUrlThumbFilePath)) {
                $photoUrlThumbFilePath = Config::get('app.imageUrl') . "/property-photos/{$updatePhoto['property_id']}" . "/{$updatePhoto['photo_name']}_200x200.{$updatePhoto['file_ext']}";
            }else {
                $photoUrlThumbFilePath = Config::get('app.imageUrl') . "/property-photos/{$updatePhoto['property_id']}" . "/{$updatePhoto['photo_name']}_thumbnail.{$updatePhoto['file_ext']}";
            }

            $responsePropertyPhoto = [];
            $responsePropertyPhoto[] =
                [
                    'id' => $updatePhoto['id'],
                    'property_id' => $updatePhoto['property_id'],
                    'property_photo_category_id' => $updatePhoto['property_photo_category_id'],
                    'property_photo_category_name' => $getPhotoCategory['category_name'],
                    'photo_name' => $updatePhoto['photo_name'],
                    'file_ext' => $updatePhoto['file_ext'],
                    'photo_url' => $photoUrlFilePath,
                    'photo_url_thump' => $photoUrlThumbFilePath,
                    'is_default' => $updatePhoto['is_default'],
                    'is_temp' => $updatePhoto['is_temp'],
                    'status' => $updatePhoto['status'],
                ];

            $response = ['status' => 1, 'statusCode' => 200 ,'message' => '', 'data' => $responsePropertyPhoto];


        }catch (Exception $e)
        {
            $message = $e->getFile().' '.$e->getLine().' '.$e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
            $response['status'] = false;
        }

        return output($response);
    }

    public function getPropertyRoomPhoto($params)
    {
        $response = ['status' => false, 'statusCode' => 500, 'message' => '', 'data' => null];
        try {
            $propertyId = $params['property_id'];
            $roomId = $params['room_id'];
            $roomCategory = 11; // For room category priority


            $getPropertyRoomCriteria =
                [
                    'criteria' =>
                        [
                            ['field' => 'id', 'condition' => '=', 'value' => $roomId],
                            ['field' => 'property_id', 'condition' => '=', 'value' => $propertyId],
                        ],
                    'firstRow' => 1
                ];
            $roomInfo = $this->propertyRoomService->select($getPropertyRoomCriteria);
            $roomInfo = $roomInfo['data'] ? $roomInfo['data'] : [];
            if(!$roomInfo){
                throw new ApiErrorException(lang('Property room not found'));
            }


            $getPropertyPhotoCriteria =
                [
                    'criteria' =>
                        [
                            ['field' => 'property_id', 'condition' => '=', 'value' => $propertyId],
                            ['field' => 'status', 'condition' => '=', 'value' => 1],
                        ],
                    'with' => ['propertyRooms.propertyRoom'],
                    'orderBy' =>
                        [
                            ["field" => "photo_order", "value" => "ASC"]
                        ],
                ];
            $getPropertyPhotos = $this->propertyPhotoRepository->findByCriteria($getPropertyPhotoCriteria);
            $getPropertyPhotos = $getPropertyPhotos ? $getPropertyPhotos : null;


            $getPropertyPhotos = collect($getPropertyPhotos)->map(function ($value)  {
                $response = $value ;

                $propertyRoomPhotos = collect($value['property_rooms'])
                    ->map(function ($value) {
                        return $value['property_room'] ;
                    })->values()->all();

                $response['property_rooms'] = $propertyRoomPhotos;
                return $response ;
            })->values()->all();

            if (empty($getPropertyPhotos)) {
                throw new ApiErrorException(lang('Property photos not found'));
            }

            $getPropertyRoomPhotoCriteria =
                [
                    'criteria' =>
                        [
                            ['field' => 'property_id', 'condition' => '=', 'value' => $propertyId],
                        ],
                    'with' => ['propertyRoom']
                ];
            $roomPhotos = $this->propertyRoomPhotoMappingService->select($getPropertyRoomPhotoCriteria);
            $roomPhotos = $roomPhotos['data'] ? $roomPhotos['data'] : [];


            $roomPhotos = collect($roomPhotos);


            $roomPhotos = $roomPhotos->map(function ($value)  {
                $response = $value ;
                $response['room_type_id'] = $value['property_room']['room_type_id'];
                unset($response['property_room']);
                return $response ;
            });


            $filteredList = [];
            $showRecommended = true ;
            foreach ($getPropertyPhotos as $key => $getPropertyPhoto) {

                $checkMapping = $roomPhotos
                    ->where('photo_id', '=', $getPropertyPhoto['id'])
                    ->where('room_id', '=', $roomId)
                    ->first();

                $requestedRooms = collect($getPropertyPhoto['property_rooms'])
                    ->where('room_type_id', '=', $roomInfo['room_type_id'])
                    ->keyBy('id')->keys();


                $checkRecommended = $roomPhotos
                    ->where('photo_id', '=', $getPropertyPhoto['id'])
                    ->whereIn('room_id',  $requestedRooms)
                    ->first();

                if($checkMapping){
                    $showRecommended = false ;
                }

                $photoUrlFilePath = Config::get('app.fileSystemDriver') . "/property-photos/{$getPropertyPhoto['property_id']}" . "/{$getPropertyPhoto['photo_name']}_1024x768.{$getPropertyPhoto['file_ext']}";
                $photoUrlThumbFilePath = Config::get('app.fileSystemDriver') . "/property-photos/{$getPropertyPhoto['property_id']}" . "/{$getPropertyPhoto['photo_name']}_200x200.{$getPropertyPhoto['file_ext']}";

                if (File::exists($photoUrlFilePath)) {
                    $photoUrlFilePath = Config::get('app.imageUrl') . "/property-photos/{$getPropertyPhoto['property_id']}" . "/{$getPropertyPhoto['photo_name']}_1024x768.{$getPropertyPhoto['file_ext']}";
                }else {
                    $photoUrlFilePath = Config::get('app.imageUrl') . "/property-photos/{$getPropertyPhoto['property_id']}" . "/{$getPropertyPhoto['photo_name']}_medium.{$getPropertyPhoto['file_ext']}";
                }

                if (File::exists($photoUrlThumbFilePath)) {
                    $photoUrlThumbFilePath = Config::get('app.imageUrl') . "/property-photos/{$getPropertyPhoto['property_id']}" . "/{$getPropertyPhoto['photo_name']}_200x200.{$getPropertyPhoto['file_ext']}";
                }else{
                    $photoUrlThumbFilePath = Config::get('app.imageUrl') . "/property-photos/{$getPropertyPhoto['property_id']}" . "/{$getPropertyPhoto['photo_name']}_thumbnail.{$getPropertyPhoto['file_ext']}";
                }

                $filteredItem = [
                    'id' => $getPropertyPhoto['id'],
                    'property_id' => $getPropertyPhoto['property_id'],
                    'property_photo_category_id' => $getPropertyPhoto['property_photo_category_id'],
                    'photo_url' => $photoUrlFilePath,
                    'photo_url_thump' => $photoUrlThumbFilePath,
                    "photo_name" => $getPropertyPhoto["photo_name"],
                    "photo_rank" => $getPropertyPhoto["photo_rank"],
                    "file_size" => $getPropertyPhoto["file_size"],
                    "file_ext" => $getPropertyPhoto["file_ext"],
                    "photo_resolution" => $getPropertyPhoto["photo_resolution"],
                    "photo_order" => $getPropertyPhoto["photo_order"],
                    "is_default" => $getPropertyPhoto["is_default"],
                    "is_temp" => $getPropertyPhoto["is_temp"],
                    "status" => $getPropertyPhoto["status"],
                    "is_selected" => $checkMapping ? true : false,
                    "is_recommended" => $checkRecommended ? true : false,
                    'order_priority' => $getPropertyPhoto['property_photo_category_id'] == $roomCategory ? 0 : 1 ,
                ];
                $filteredList[] = $filteredItem ;

            }

            if(collect($filteredList)->where('is_recommended', 'true')->count() == 0){
                $showRecommended = false ;
            }
            array_multisort(
                array_column($filteredList, 'order_priority'), SORT_ASC,
                array_column($filteredList, 'photo_order'), SORT_ASC,
                $filteredList
            );

            $response = ['status' => 1, 'statusCode' => 200, 'message' => '', 'data' => ['get_room_photos' => $filteredList, 'show_recommended' => $showRecommended] ];

        } catch (ApiErrorException $e) {
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 204;
        } catch (Exception $e) {
            $message = $e->getFile() . ' ' . $e->getLine() . ' ' . $e->getMessage();
            Log::error($message);
        }
        return output($response);
    }

    public function uploadPhoto($params = []){

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

            $uploadedFile = $params['photo'];
            $validationResult = $this->propertyPhotoValidator->validate($validateParams);
            if ($validationResult->errors()->first()) {
                throw new ApiErrorException($validationResult->errors()->all());
            }

            $uploadedOriginalImage =  Image::make($uploadedFile);
            $imageWidth = $uploadedOriginalImage->width() ;
            $imageHeight = $uploadedOriginalImage->height();

            $fileExt = $uploadedFile->getClientOriginalExtension();
            $fileSize = (int)ceil(Image::make($uploadedFile)->filesize() / 1024);

            $imageExtension = 'jpg';
            $fileExt = $fileExt != $imageExtension ? $imageExtension : $fileExt;
            $quality = 80;

            $urlPath =  '/property-photos/' . $params['property_id'] . "/";
            $filePath = Config::get('app.fileSystemDriver') . $urlPath ;
            $fileName = time().'_'.generateRandomString(10); ;

            if (!File::exists($filePath)) {
                File::makeDirectory($filePath, 0777, true);
            }
            $originalImageMustResize = ($imageHeight > 2000 || $imageWidth > 2000)  ;

            if($imageHeight < 768){
                throw new ApiErrorException('image size error: minimum height must be 768px') ;
            }


            if ($imageHeight > $imageWidth) {

                $ratio = $imageHeight/768;
                //$ratio200 = 768/200;
                $resizeWidth = intval($imageWidth/$ratio);
                //$resizeThumbWidth = intval($resizeWidth/$ratio200);

                if($originalImageMustResize){
                    $imageHRatio = $imageHeight / 2000 ;
                    $imageResizedOriginalWidth = intval($imageWidth / $imageHRatio);
                    $image = $uploadedOriginalImage->fit($imageResizedOriginalWidth, 2000)->encode($imageExtension, $quality)->orientate()->save($filePath . $fileName . '.' . $fileExt, $quality) ;
                }else{
                    $image = $uploadedOriginalImage->encode($imageExtension, $quality)->orientate()->save($filePath . $fileName . '.' . $fileExt, $quality) ;
                }
                $image->fit($resizeWidth, 768)->encode($imageExtension, $quality)->orientate()->save($filePath . $fileName . '_medium' . '.' . $fileExt);
                $image->fit(300,300)->encode($imageExtension, $quality)->orientate()->save($filePath . $fileName . '_thumbnail' . '.' . $fileExt );
            }
            else{

                $ratio = $imageHeight/768;
                $resizeWidth = intval($imageWidth/$ratio);

                $ratioTumbnail = 768/300;
                $resizeThumbWidth = intval($resizeWidth/$ratioTumbnail);


                if($originalImageMustResize){
                    $imageWRatio = $imageWidth / 2000 ;
                    $imageResizedOriginalHeight = intval($imageHeight / $imageWRatio);
                    $image = $uploadedOriginalImage->fit(2000, $imageResizedOriginalHeight)->encode($imageExtension, $quality)->orientate()->save($filePath . $fileName . '.' . $fileExt, $quality) ;
                }else{
                    $image = $uploadedOriginalImage->encode($imageExtension, $quality)->orientate()->save($filePath . $fileName . '.' . $fileExt, $quality) ;
                }

                if($resizeWidth > 1599){
                    $image->fit(1600, 768)->encode($imageExtension, $quality)->orientate()->save($filePath . $fileName . '_medium' . '.' . $fileExt);
                    $image->fit(300,300)->encode($imageExtension, $quality)->orientate()->save($filePath . $fileName . '_thumbnail' . '.' . $fileExt);
                }
                else{
                    $image->fit($resizeWidth, 768)->encode($imageExtension, $quality)->orientate()->save($filePath . $fileName . '_medium' . '.' . $fileExt);
                    $image->fit(300)->encode($imageExtension, $quality)->orientate()->save($filePath . $fileName . '_thumbnail' . '.' . $fileExt);
                }

            }

            $isCompatibleWithMywebSlider = 0;
            if($imageWidth >= 1150 && $imageHeight >= 600){
                $isCompatibleWithMywebSlider = 1;
            }

            $response = [
                'status' => true,
                'data' => [
                    'photo_path' => $urlPath,
                    'photo_name' => $fileName,
                    'file_size' => $fileSize,
                    'file_ext' => $fileExt,
                    'file_resolution' => $imageWidth .'x'. $imageHeight,
                    'is_compatible_with_myweb_slider' => $isCompatibleWithMywebSlider
                ]
            ];
        }catch (Exception $e)
        {
            $message = $e->getFile().' '.$e->getLine().' '.$e->getMessage();
            Log::error($message);
            $response['message'] = $e->getMessage();
            $response['status'] = false;
        }

        return output($response);
    }

    public function getPropertyPlacePhoto($params)
    {
        $response = ['status' => false, 'statusCode' => 500, 'message' => '', 'data' => null];
        try {
            $propertyId = $params['property_id'];
            $placeId = $params['place_id'];
            $placeCategory = 0;
            $getPropertyPlaceCriteria =
                [
                    'criteria' =>
                        [
                            ['field' => 'id', 'condition' => '=', 'value' => $placeId],
                            ['field' => 'property_id', 'condition' => '=', 'value' => $propertyId],
                        ],
                    'firstRow' => 1
                ];
            $placeInfo = $this->propertyPlaceService->select($getPropertyPlaceCriteria);
            $placeInfo = $placeInfo['data'] ? $placeInfo['data'] : [];

            if(!$placeInfo){
                throw new ApiErrorException(lang('Property place not found'));
            }


            $getPropertyPhotoCriteria =
                [
                    'criteria' =>
                        [
                            ['field' => 'property_id', 'condition' => '=', 'value' => $propertyId],
                            ['field' => 'status', 'condition' => '=', 'value' => 1],
                        ],
                    'with' => ['propertyPlaces.propertyPlace'],
                    'orderBy' =>
                        [
                            ["field" => "photo_order", "value" => "ASC"]
                        ],
                ];
            $getPropertyPhotos = $this->propertyPhotoRepository->findByCriteria($getPropertyPhotoCriteria);
            $getPropertyPhotos = $getPropertyPhotos ? $getPropertyPhotos : null;


            $getPropertyPhotos = collect($getPropertyPhotos)->map(function ($value)  {
                $response = $value ;

                $propertyPlacePhotos = collect($value['property_places'])
                    ->map(function ($value) {
                        return $value['property_place'] ;
                    })->values()->all();

                $response['property_places'] = $propertyPlacePhotos;
                return $response ;
            })->values()->all();

            if (empty($getPropertyPhotos)) {
                throw new ApiErrorException(lang('Property photos not found'));
            }

            $getPropertyPlacePhotoCriteria =
                [
                    'criteria' =>
                        [
                            ['field' => 'property_id', 'condition' => '=', 'value' => $propertyId],
                        ],
                    'with' => ['propertyPlace']
                ];
            $placePhotos = $this->propertyPlacePhotoMappingRepository->findByCriteria($getPropertyPlacePhotoCriteria);

            $placePhotos = $placePhotos ? $placePhotos : [];


            $placePhotos = collect($placePhotos);


            $placePhotos = $placePhotos->map(function ($value)  {
                $response = $value ;
                $response['place_category_id'] = $value['property_place']['place_category_id'];
                unset($response['property_place']);
                return $response ;
            });


            $filteredList = [];
            $showRecommended = true ;
            foreach ($getPropertyPhotos as $key => $getPropertyPhoto) {

                $checkMapping = $placePhotos
                    ->where('photo_id', '=', $getPropertyPhoto['id'])
                    ->where('place_id', '=', $placeId)
                    ->first();

                $requestedPlaces = collect($getPropertyPhoto['property_places'])
                    ->where('place_category_id', '=', $placeInfo['place_category_id'])
                    ->keyBy('id')->keys();


                $checkRecommended = $placePhotos
                    ->where('photo_id', '=', $getPropertyPhoto['id'])
                    ->whereIn('place_id',  $requestedPlaces)
                    ->first();

                if($checkMapping){
                    $showRecommended = false ;
                }

                $photoUrlFilePath = Config::get('app.fileSystemDriver') . "/property-photos/{$getPropertyPhoto['property_id']}" . "/{$getPropertyPhoto['photo_name']}_1024x768.{$getPropertyPhoto['file_ext']}";
                $photoUrlThumbFilePath = Config::get('app.fileSystemDriver') . "/property-photos/{$getPropertyPhoto['property_id']}" . "/{$getPropertyPhoto['photo_name']}_200x200.{$getPropertyPhoto['file_ext']}";

                if (File::exists($photoUrlFilePath)) {
                    $photoUrlFilePath = Config::get('app.imageUrl') . "/property-photos/{$getPropertyPhoto['property_id']}" . "/{$getPropertyPhoto['photo_name']}_1024x768.{$getPropertyPhoto['file_ext']}";
                }else {
                    $photoUrlFilePath = Config::get('app.imageUrl') . "/property-photos/{$getPropertyPhoto['property_id']}" . "/{$getPropertyPhoto['photo_name']}_medium.{$getPropertyPhoto['file_ext']}";
                }

                if (File::exists($photoUrlThumbFilePath)) {
                    $photoUrlThumbFilePath = Config::get('app.imageUrl') . "/property-photos/{$getPropertyPhoto['property_id']}" . "/{$getPropertyPhoto['photo_name']}_200x200.{$getPropertyPhoto['file_ext']}";
                }else{
                    $photoUrlThumbFilePath = Config::get('app.imageUrl') . "/property-photos/{$getPropertyPhoto['property_id']}" . "/{$getPropertyPhoto['photo_name']}_thumbnail.{$getPropertyPhoto['file_ext']}";
                }

                $filteredItem = [
                    'id' => $getPropertyPhoto['id'],
                    'property_id' => $getPropertyPhoto['property_id'],
                    'property_photo_category_id' => $getPropertyPhoto['property_photo_category_id'],
                    'photo_url' => $photoUrlFilePath,
                    'photo_url_thump' => $photoUrlThumbFilePath,
                    "photo_name" => $getPropertyPhoto["photo_name"],
                    "photo_rank" => $getPropertyPhoto["photo_rank"],
                    "file_size" => $getPropertyPhoto["file_size"],
                    "file_ext" => $getPropertyPhoto["file_ext"],
                    "photo_resolution" => $getPropertyPhoto["photo_resolution"],
                    "photo_order" => $getPropertyPhoto["photo_order"],
                    "is_default" => $getPropertyPhoto["is_default"],
                    "is_temp" => $getPropertyPhoto["is_temp"],
                    "status" => $getPropertyPhoto["status"],
                    "is_selected" => $checkMapping ? true : false,
                    "is_recommended" => $checkRecommended ? true : false,
                    'order_priority' => $getPropertyPhoto['property_photo_category_id'] == $placeCategory ? 0 : 1 ,
                ];
                $filteredList[] = $filteredItem ;

            }

            if(collect($filteredList)->where('is_recommended', 'true')->count() == 0){
                $showRecommended = false ;
            }
            array_multisort(
                array_column($filteredList, 'order_priority'), SORT_ASC,
                array_column($filteredList, 'photo_order'), SORT_ASC,
                $filteredList
            );

            $response = ['status' => 1, 'statusCode' => 200, 'message' => '', 'data' => ['get_place_photos' => $filteredList, 'show_recommended' => $showRecommended] ];

        } catch (ApiErrorException $e) {
            $response['message'] = $e->getMessage();
            $response['statusCode'] = 204;
        } catch (Exception $e) {
            $message = $e->getFile() . ' ' . $e->getLine() . ' ' . $e->getMessage();
            Log::error($message);
        }
        return output($response);
    }

}
