src/Model/CalendarModel.php line 224

Open in your IDE?
  1. <?php
  2. namespace App\Model;
  3. use Symfony\Component\Security\Core\User\UserInterface;
  4. use Pimcore\Model\DataObject\CustomNotification;
  5. use Pimcore\Model\DataObject\EwsNotification;
  6. use Symfony\Component\HttpFoundation\Request;
  7. use App\Service\MeteomaticsWeatherService;
  8. use Pimcore\Model\DataObject\Dashboard;
  9. use Pimcore\Model\DataObject\Customer;
  10. use Pimcore\Model\DataObject\Location;
  11. use Pimcore\Model\DataObject;
  12. use App\Model\LocationModel;
  13. use GuzzleHttp\Client;
  14. use DateTimeZone;
  15. use Pimcore\Db;
  16. use DateTime;
  17. class CalendarModel
  18. {
  19.     private $apiBaseUrl MATEOMATICS_API_URL;
  20.     private $username MATEOMATICS_API_USERNAME;
  21.     private  $password MATEOMATICS_API_PASSWORD;
  22.     // public function getCalendarNotification(MeteomaticsWeatherService $mateoMaticsService, $user, $customNotificationIds, $startDate, $endDate, $hour, $page, $size, $title, $paginator, $translator): array
  23.     // {
  24.     //     $pageSize = isset($size) ? $size : LIMIT_PER_PAGE;
  25.     //     $page = isset($page) ? $page : 1;
  26.     //     $qualifiedLocations = [];
  27.     //     $locationModel = new LocationModel();
  28.     //     $ewsNotificationModel = new EwsNotificationModel();
  29.     //     $options = [];
  30.     //     $calculateOption = [];
  31.     //     $customNotificationListing = new DataObject\CustomNotification\Listing();
  32.     //     foreach ($customNotificationListing->getClass()->getFieldDefinitions() as $fieldDefionition) {
  33.     //         if ($fieldDefionition->getName() == "calculate") {
  34.     //             $options = $fieldDefionition->getOptions();
  35.     //         }
  36.     //     }
  37.     //     if ($options) {
  38.     //         foreach ($options as $optionKey => $option) {
  39.     //             $calculateOption[$option['value']] = $option['key'];
  40.     //         }
  41.     //     }
  42.     //     $customNotification = new DataObject\CustomNotification\Listing();
  43.     //     $customNotification->addConditionParam('o_id IN (' . $customNotificationIds . ')');
  44.     //     $customNotification->filterByUser($user);
  45.     //     //$customNotification->setLimit(10);
  46.     //     $customNotification->setOrderKey("o_id");
  47.     //     $customNotification->setOrder("desc");
  48.     //     if (!empty($title)) {
  49.     //         $customNotification->addConditionParam("title like '%$title%' ");
  50.     //     }
  51.     //     $paginator = $paginator->paginate(
  52.     //         $customNotification,
  53.     //         $page,
  54.     //         $pageSize
  55.     //     );
  56.     //     $customNotifications = $paginator->count();
  57.     //     if (!$customNotifications) {
  58.     //         // throw new \Exception("You do not have any notification configured for this location");
  59.     //         return ['success' => false, 'message' => $translator->trans("you_do_not_have_any_notification_configured_for_this_location")];
  60.     //     }
  61.     //     $resultArr = [];
  62.     //     $resultArr1 = [];
  63.     //     foreach ($paginator as $customNotification) {
  64.     //         $user = $customNotification->getUser();
  65.     //         $location = $customNotification->getLocation();
  66.     //         if ($location instanceof DataObject\Location) {
  67.     //             $coOrdinates = json_decode($location->getCoOrdinates(), true);
  68.     //             if ($coOrdinates && count($coOrdinates)) {
  69.     //                 if (!$customNotification->getAlert()) {
  70.     //                     continue;
  71.     //                 }
  72.     //                 $parameter = $customNotification->getAlert()->getMeteoMaticsKey();
  73.     //                 $alertName = $customNotification->getAlert()->getName("en");
  74.     //                 $alertNameAr = $customNotification->getAlert()->getName("ar");
  75.     //                 if (!empty($customNotification->getWeatherModel())) {
  76.     //                     $model = $customNotification->getWeatherModel();
  77.     //                 } else {
  78.     //                     $model = "mix";
  79.     //                 }
  80.     //                 $startDate = date('Y-m-d\T00:00:00.v\Z', strtotime($startDate));
  81.     //                 $endDate = date('Y-m-d\T23:59:59.v\Z', strtotime($endDate));
  82.     //                 p_r($startDate);
  83.     //                 p_r($endDate);
  84.     //                 $response = $mateoMaticsService->getTempratureByParamsHourly($coOrdinates, $startDate, $endDate, $parameter, $hour, $model);
  85.     //                 $qualifiedLocations = $response['data'][0]['coordinates'][0]['dates'];
  86.     //                 if (is_array($response) && isset($response['data'][0]['parameter']) && $response['data'][0]['parameter'] = $parameter) {
  87.     //                     foreach ($qualifiedLocations as $key => $qualifiedLocation) {
  88.     //                         if ($customNotification->getCalculate() == "range") {
  89.     //                             $value2 = [];
  90.     //                             $value2[0] = $customNotification->getMinValue();
  91.     //                             $value2[1] = $customNotification->getMaxValue();
  92.     //                         } else {
  93.     //                             $value2 = $customNotification->getMaxValue();
  94.     //                         }
  95.     //                         $value = $qualifiedLocation['value'];
  96.     //                         $resultArr[$qualifiedLocation["date"]][$alertName] = $qualifiedLocation;
  97.     //                         if (\App\Lib\Utility::compareValues($customNotification->getCalculate(), $value, $value2)) {
  98.     //                             $resultArr1[] = [
  99.     //                                 'custom_notification_id' => $customNotification->getId(),
  100.     //                                 'custom_notification_id' => $customNotification->getId(),
  101.     //                                 "custom_notification_color" => $customNotification->getColor(),
  102.     //                                 "date" => $qualifiedLocation['date'],
  103.     //                                 "location_name" => $location->getName(),
  104.     //                                 "location_title" => $location->getTitle(),
  105.     //                                 "custom_notification_title" => $customNotification->getTitle(),
  106.     //                                 "location_id" => $location->getId(),
  107.     //                                 "parameter" => $parameter,
  108.     //                                 "name" => $alertName,
  109.     //                                 "nameAr" => $alertNameAr,
  110.     //                                 "calculation_type" => $customNotification->getCalculate(),
  111.     //                                 "calculation_type_label" => isset($calculateOption[$customNotification->getCalculate()]) ? $calculateOption[$customNotification->getCalculate()] : "",
  112.     //                                 "user_value" => $value2,
  113.     //                                 'received_value' => $value,
  114.     //                                 "matched" => true
  115.     //                             ];
  116.     //                         } else {
  117.     //                             $resultArr1[] = [
  118.     //                                 'custom_notification_id' => $customNotification->getId(),
  119.     //                                 "custom_notification_color" => $customNotification->getColor(),
  120.     //                                 "date" => $qualifiedLocation['date'],
  121.     //                                 "location_name" => $location->getName(),
  122.     //                                 "location_title" => $location->getTitle(),
  123.     //                                 "custom_notification_title" => $customNotification->getTitle(),
  124.     //                                 "location_id" => $location->getId(),
  125.     //                                 "parameter" => $parameter,
  126.     //                                 "name" => $alertName,
  127.     //                                 "nameAr" => $alertNameAr,
  128.     //                                 "calculation_type" => $customNotification->getCalculate(),
  129.     //                                 "calculation_type_label" => isset($calculateOption[$customNotification->getCalculate()]) ? $calculateOption[$customNotification->getCalculate()] : "",
  130.     //                                 "user_value" => $value2,
  131.     //                                 'received_value' => $value,
  132.     //                                 "matched" => false
  133.     //                             ];
  134.     //                         }
  135.     //                     }
  136.     //                 }
  137.     //             }
  138.     //         }
  139.     //     }
  140.     //     $rawArr = array_values($resultArr1);
  141.     //     $organizedData = [];
  142.     //     $matchedAlert = [];
  143.     //     $timezone = new \DateTimeZone("Asia/Riyadh");
  144.     //     foreach ($rawArr as $entry) {
  145.     //         $notification = $entry;
  146.     //         // Parse the date with DateTime and adjust timezone
  147.     //         $notificationDate = new \DateTime($notification['date'], new \DateTimeZone("UTC"));
  148.     //         $notificationDate->modify('-6 hours');
  149.     //         $notificationDate->setTimezone($timezone);
  150.     //         // Format date components for use in organizedData
  151.     //         $notification['date'] = $notificationDate->format("Y-m-d\TH:00:00\Z");
  152.     //         $notificationId = $notification['custom_notification_id'];
  153.     //         $date = $notificationDate->format("Y-m-d");
  154.     //         $time = $notificationDate->format("H:i");
  155.     //         $day = $notificationDate->format("D");
  156.     //         if (!isset($matchedAlert[$date . $notificationId]) || $notification['matched'] == true) {
  157.     //             $matchedAlert[$date . $notificationId] = $notification['matched'];
  158.     //         }
  159.     //         // Initialize the main array element for this notification ID if not already done
  160.     //         if (!isset($organizedData[$notificationId])) {
  161.     //             $organizedData[$notificationId] = [
  162.     //                 "custom_notification_title" => $notification['custom_notification_title'],
  163.     //                 "location_title" => $notification['location_title'],
  164.     //                 "alerts" => [],
  165.     //                 "user_value" => $notification['user_value'], // Static value, change as needed
  166.     //                 "calculation_type" => $notification['calculation_type'],
  167.     //                 "calculation_type_label" => $notification['calculation_type_label'],
  168.     //                 "parameterName" => $notification['parameter'],
  169.     //                 "parameterTitleEn" => $notification['name'],
  170.     //                 "parameterTitleAr" => $notification['nameAr'],
  171.     //             ];
  172.     //         }
  173.     //         // Initialize the date array element if not already done
  174.     //         if (!isset($organizedData[$notificationId]['alerts'][$date])) {
  175.     //             $organizedData[$notificationId]['alerts'][$date] = [
  176.     //                 'date' => $date,
  177.     //                 'day' => $day,
  178.     //                 'rawDate' => $notification['date'],
  179.     //                 'data' => []
  180.     //             ];
  181.     //         }
  182.     //         $organizedData[$notificationId]['alerts'][$date]["isAlertPresent"] = $matchedAlert[$date . $notificationId];
  183.     //         // Append time data to the corresponding date
  184.     //         $organizedData[$notificationId]['alerts'][$date]['data'][] = [
  185.     //             'fromInterval' => $notification['date'],
  186.     //             'toInterval' => $notification['date'],
  187.     //             'data' => $notification
  188.     //         ];
  189.     //     }
  190.     //     return ["success" => true, "data" => array_values($organizedData), "paginationVariables" => $paginator->getPaginationData()];
  191.     // }
  192.     public function getCalendarNotification(MeteomaticsWeatherService $mateoMaticsService$user$customNotificationIds$startDate$endDate$hour$page$size$title$paginator$translator$tagIds ''$location ''$locationTagName): array
  193.     {
  194.         // Set timezone to Asia/Riyadh
  195.         $timezone = new \DateTimeZone("Asia/Riyadh");
  196.         // Convert start and end dates to Asia/Riyadh timezone
  197.         $startDateObj = new \DateTime($startDate$timezone);
  198.         $endDateObj = new \DateTime($endDate$timezone);
  199.         $pageSize = isset($size) ? $size LIMIT_PER_PAGE;
  200.         $page = isset($page) ? $page 1;
  201.         $qualifiedLocations = [];
  202.         $locationModel = new LocationModel();
  203.         $ewsNotificationModel = new EwsNotificationModel();
  204.         $options = [];
  205.         $calculateOption = [];
  206.         $customNotificationListing = new DataObject\CustomNotification\Listing();
  207.         foreach ($customNotificationListing->getClass()->getFieldDefinitions() as $fieldDefionition) {
  208.             if ($fieldDefionition->getName() == "calculate") {
  209.                 $options $fieldDefionition->getOptions();
  210.             }
  211.         }
  212.         if ($options) {
  213.             foreach ($options as $optionKey => $option) {
  214.                 $calculateOption[$option['value']] = $option['key'];
  215.             }
  216.         }
  217.         // Check if $customNotificationIds is empty and return a message if so
  218.         if (empty($customNotificationIds)) {
  219.             return ['success' => false'message' => $translator->trans("you_do_not_have_any_notification_configured")];
  220.         }
  221.         $customNotification = new DataObject\CustomNotification\Listing();
  222.         $customNotification->addConditionParam('o_id IN (' $customNotificationIds ')');
  223.         $customNotification->filterByUser($user);
  224.         $customNotification->setOrderKey("o_id");
  225.         $customNotification->setOrder("desc");
  226.         if (!empty($title)) {
  227.             $customNotification->addConditionParam("title like '%$title%' ");
  228.         }
  229.         if (!empty($tagIds)) {
  230.             $customNotification->addConditionParam('tag__id IN (' $tagIds ')');
  231.         }
  232.         // filter for location title
  233.         if (!empty($location)) {
  234.             $db \Pimcore\Db::get();
  235.             $locationIds $db->fetchFirstColumn(
  236.                 "SELECT l.oo_id FROM object_query_location AS l WHERE l.title LIKE :location;",
  237.                 [
  238.                     'location' => '%' $location '%',
  239.                 ]
  240.             );
  241.             if (!empty($locationIds)) {
  242.                 // Combine conditions with OR
  243.                 $conditions = [];
  244.                 if (!empty($locationIds)) {
  245.                     $conditions[] = 'location__id IN (' implode(","$locationIds) . ')';
  246.                 }
  247.                 if (!empty($tagIds)) {
  248.                     $conditions[] = 'tag__id IN (' implode(","$tagIds) . ')';
  249.                 }
  250.                 $customNotification->addConditionParam(implode(" OR "$conditions));
  251.             } else {
  252.                 return ['success' => false'message' => $translator->trans("you_do_not_have_any_notification_configured_for_this_location")];
  253.             }
  254.         }
  255.         // filter for location name
  256.         if (!empty($locationTagName)) {
  257.             $db \Pimcore\Db::get();
  258.            
  259.             $tagIds $db->fetchFirstColumn(
  260.                 "SELECT ooo_id 
  261.                 FROM object_localized_data_Tags
  262.                 WHERE language = :language AND TagName LIKE :tagName",
  263.                 [
  264.                     'language' => $translator->getLocale(),
  265.                     'tagName' => '%' $location '%'
  266.                 ]
  267.             );
  268.             if (!empty($tagIds)) {
  269.                 // Combine conditions with OR
  270.                 $conditions = [];
  271.                 if (!empty($locationIds)) {
  272.                     $conditions[] = 'location__id IN (' implode(","$locationIds) . ')';
  273.                 }
  274.                 if (!empty($tagIds)) {
  275.                     $conditions[] = 'tag__id IN (' implode(","$tagIds) . ')';
  276.                 }
  277.                 $customNotification->addConditionParam(implode(" OR "$conditions));
  278.             } else {
  279.                 return ['success' => false'message' => $translator->trans("you_do_not_have_any_notification_configured_for_this_location")];
  280.             }
  281.         }
  282.         $paginator $paginator->paginate(
  283.             $customNotification,
  284.             $page,
  285.             $pageSize
  286.         );
  287.         $customNotifications $paginator->count();
  288.         if (!$customNotifications) {
  289.             return ['success' => false'message' => $translator->trans("you_do_not_have_any_notification_configured_for_this_location")];
  290.         }
  291.         $resultArr = [];
  292.         $resultArr1 = [];
  293.         $comparableStartDate $startDateObj;
  294.         $comparableEndDate $endDateObj;
  295.         $startDateFormatted $startDateObj->format('Y-m-d\T00:00:00.v\Z');
  296.         $endDateObj->modify("+3 hours");
  297.         $endDateFormatted $endDateObj->format('Y-m-d\T00:00:00.v\Z');
  298.         foreach ($paginator as $customNotification) {
  299.             $user $customNotification->getUser();
  300.             $location $customNotification->getLocation();
  301.             if ($location instanceof DataObject\Location) {
  302.                 $coOrdinates json_decode($location->getCoOrdinates(), true);
  303.                 if ($coOrdinates && count($coOrdinates)) {
  304.                     if (!$customNotification->getAlert()) {
  305.                         continue;
  306.                     }
  307.                     $parameter $customNotification->getAlert()->getMeteoMaticsKey();
  308.                     $alertName $customNotification->getAlert()->getName("en");
  309.                     $alertNameAr $customNotification->getAlert()->getName("ar");
  310.                     $model = !empty($customNotification->getWeatherModel()) ? $customNotification->getWeatherModel() : "mix";
  311.                     // Format dates for Meteomatics request with Asia/Riyadh timezone
  312.                     /*$startDateFormatted = $startDateObj->format('Y-m-d\T00:00:00.v\Z');
  313.             $endDateObj->modify("+3 hours");
  314.             $endDateFormatted = $endDateObj->format('Y-m-d\T00:00:00.v\Z');*/
  315.                     $response $mateoMaticsService->getTempratureByParamsHourly($coOrdinates$startDateFormatted$endDateFormatted$parameter$hour$model$timezone);
  316.                     $qualifiedLocations $response['data'][0]['coordinates'][0]['dates'];
  317.                     if (is_array($response) && isset($response['data'][0]['parameter']) && $response['data'][0]['parameter'] == $parameter) {
  318.                         foreach ($qualifiedLocations as $key => $qualifiedLocation) {
  319.                             $qualifiedDate = new \DateTime($qualifiedLocation["date"], $timezone);
  320.                             // Check if the qualified date falls within the start and end dates
  321.                             //                var_dump("Qualified-Data : ". $qualifiedDate->format("Y-m-d")." --- ".$comparableEndDate->format("Y-m-d"));
  322.                             if ($qualifiedDate $comparableStartDate || $qualifiedDate $comparableEndDate) {
  323.                                 continue; // Skip if date is out of the specified range
  324.                             }
  325.                             if ($customNotification->getCalculate() == "range") {
  326.                                 $value2 = [];
  327.                                 $value2[0] = $customNotification->getMinValue();
  328.                                 $value2[1] = $customNotification->getMaxValue();
  329.                             } else {
  330.                                 $value2 $customNotification->getMaxValue();
  331.                             }
  332.                             $value $qualifiedLocation['value'];
  333.                             $resultArr[$qualifiedLocation["date"]][$alertName] = $qualifiedLocation;
  334.                             if (\App\Lib\Utility::compareValues($customNotification->getCalculate(), $value$value2)) {
  335.                                 $resultArr1[] = [
  336.                                     'custom_notification_id' => $customNotification->getId(),
  337.                                     "custom_notification_color" => $customNotification->getColor(),
  338.                                     'model' => $customNotification->getWeatherModel(),
  339.                                     'unit' => $customNotification->getUnits(),
  340.                                     'unit_en' => $customNotification->getAlert()?->getUnitTitle(),
  341.                                     'unit_ar' => (\App\Lib\Utility::getArabicTranslationUnits($customNotification->getAlert()?->getUnitTitle())),
  342.                                     "date" => $qualifiedLocation['date'],
  343.                                     "location_name" => $location->getName(),
  344.                                     "location_title" => $location->getTitle(),
  345.                                     "custom_notification_title" => $customNotification->getTitle(),
  346.                                     "location_id" => $location->getId(),
  347.                                     "parameter" => $parameter,
  348.                                     "name" => $alertName,
  349.                                     "nameAr" => $alertNameAr,
  350.                                     "calculation_type" => $customNotification->getCalculate(),
  351.                                     'calculculation_type_ar' => (\App\Lib\Utility::getArabicTranslation($customNotification->getCalculate(), CUSTOM_NOTIFICATION_CONDITION) ? \App\Lib\Utility::getArabicTranslation($customNotification->getCalculate(), CUSTOM_NOTIFICATION_CONDITION) : ''),
  352.                                     "calculation_type_label" => isset($calculateOption[$customNotification->getCalculate()]) ? $calculateOption[$customNotification->getCalculate()] : "",
  353.                                     "calculation_type_label" => $calculateOption[$customNotification->getCalculate()] ?? "",
  354.                                     "user_value" => $value2,
  355.                                     'received_value' => $value,
  356.                                     "matched" => true
  357.                                 ];
  358.                             } else {
  359.                                 $resultArr1[] = [
  360.                                     'custom_notification_id' => $customNotification->getId(),
  361.                                     "custom_notification_color" => $customNotification->getColor(),
  362.                                     'model' => $customNotification->getWeatherModel(),
  363.                                     'unit' => $customNotification->getUnits(),
  364.                                     'unit_en' => $customNotification->getAlert()?->getUnitTitle(),
  365.                                     'unit_ar' => (\App\Lib\Utility::getArabicTranslationUnits($customNotification->getAlert()?->getUnitTitle())),
  366.                                     "date" => $qualifiedLocation['date'],
  367.                                     "location_name" => $location->getName(),
  368.                                     "location_title" => $location->getTitle(),
  369.                                     "custom_notification_title" => $customNotification->getTitle(),
  370.                                     "location_id" => $location->getId(),
  371.                                     "parameter" => $parameter,
  372.                                     "name" => $alertName,
  373.                                     "nameAr" => $alertNameAr,
  374.                                     "calculation_type" => $customNotification->getCalculate(),
  375.                                     'calculculation_type_ar' => (\App\Lib\Utility::getArabicTranslation($customNotification->getCalculate(), CUSTOM_NOTIFICATION_CONDITION) ? \App\Lib\Utility::getArabicTranslation($customNotification->getCalculate(), CUSTOM_NOTIFICATION_CONDITION) : ''),
  376.                                     "calculation_type_label" => isset($calculateOption[$customNotification->getCalculate()]) ? $calculateOption[$customNotification->getCalculate()] : "",
  377.                                     "calculation_type_label" => $calculateOption[$customNotification->getCalculate()] ?? "",
  378.                                     "user_value" => $value2,
  379.                                     'received_value' => $value,
  380.                                     "matched" => false
  381.                                 ];
  382.                             }
  383.                         }
  384.                     }
  385.                 }
  386.             }
  387.         }
  388.         $rawArr array_values($resultArr1);
  389.         $organizedData = [];
  390.         $matchedAlert = [];
  391.         $timezone = new \DateTimeZone("Asia/Riyadh");
  392.         foreach ($rawArr as $entry) {
  393.             $notification $entry;
  394.             // Parse the date with DateTime and adjust timezone
  395.             $notificationDate = new \DateTime($notification['date'], $timezone);
  396.             $notification['date'] = $notificationDate->format("Y-m-d\TH:00:00\Z");
  397.             $notificationId $notification['custom_notification_id'];
  398.             $date $notificationDate->format("Y-m-d");
  399.             $time $notificationDate->format("H:i");
  400.             $day $notificationDate->format("D");
  401.             if (!isset($matchedAlert[$date $notificationId]) || $notification['matched'] == true) {
  402.                 $matchedAlert[$date $notificationId] = $notification['matched'];
  403.             }
  404.             // Initialize the main array element for this notification ID if not already done
  405.             if (!isset($organizedData[$notificationId])) {
  406.                 $organizedData[$notificationId] = [
  407.                     "custom_notification_title" => $notification['custom_notification_title'],
  408.                     "location_title" => $notification['location_title'],
  409.                     "tag_name" => $customNotification->getTag() ? $customNotification->getTag()->getTagName() : "",
  410.                     "alerts" => [],
  411.                     "user_value" => $notification['user_value'], // Static value, change as needed
  412.                     "calculation_type" => $notification['calculation_type'],
  413.                     'calculculation_type_ar' => (\App\Lib\Utility::getArabicTranslation($customNotification->getCalculate(), CUSTOM_NOTIFICATION_CONDITION) ? \App\Lib\Utility::getArabicTranslation($customNotification->getCalculate(), CUSTOM_NOTIFICATION_CONDITION) : ''),
  414.                     "calculation_type_label" => $notification['calculation_type_label'],
  415.                     "parameterName" => $notification['parameter'],
  416.                     "parameterTitleEn" => $notification['name'],
  417.                     "parameterTitleAr" => $notification['nameAr'],
  418.                     'unit' => $notification['unit'],
  419.                     'unit_en' => $notification['unit_en'],
  420.                     'unit_ar' => $notification['unit_ar'],
  421.                 ];
  422.             }
  423.             // Initialize the date array element if not already done
  424.             if (!isset($organizedData[$notificationId]['alerts'][$date])) {
  425.                 $organizedData[$notificationId]['alerts'][$date] = [
  426.                     'date' => $date,
  427.                     'day' => $day,
  428.                     'rawDate' => $notification['date'],
  429.                     'data' => []
  430.                 ];
  431.             }
  432.             $organizedData[$notificationId]['alerts'][$date]["isAlertPresent"] = $matchedAlert[$date $notificationId];
  433.             // Append time data to the corresponding date
  434.             $organizedData[$notificationId]['alerts'][$date]['data'][] = [
  435.                 'fromInterval' => $notification['date'],
  436.                 'toInterval' => $notification['date'],
  437.                 'data' => $notification
  438.             ];
  439.         }
  440.         return ["success" => true"data" => array_values($organizedData), "paginationVariables" => $paginator->getPaginationData()];
  441.     }
  442.     // public function getAdvanceCalendarNotification(MeteomaticsWeatherService $mateoMaticsService, $user, $advanceCustomNotificationIds, $startDate, $endDate, $hour, $page, $size, $title, $paginator, $translator): array
  443.     // {
  444.     //     $qualifiedLocations = [];
  445.     //     $advanceCustomNotifications = new DataObject\AdvanceCustomNotification\Listing();
  446.     //     $advanceCustomNotifications->addConditionParam('o_id IN (' . $advanceCustomNotificationIds . ')');
  447.     //     $advanceCustomNotifications->addConditionParam('owner__id = ? OR user LIKE ? ', [$user->getId(), '%,' . $user->getId() . ',%']);
  448.     //     $advanceCustomNotifications->setOrderKey("o_id");
  449.     //     $advanceCustomNotifications->setOrder("desc");
  450.     //     if (!empty($title)) {
  451.     //         $advanceCustomNotifications->addConditionParam("notificationName like '%$title%' ");
  452.     //     }
  453.     //     $totalAdvanceCustomNotifications = $advanceCustomNotifications->count();
  454.     //     if (!$totalAdvanceCustomNotifications) {
  455.     //         // throw new \Exception("You do not have any notification configured for this location");
  456.     //         return ['success' => false, 'message' => $translator->trans("you_do_not_have_any_advance_custom_notification_configured")];
  457.     //     }
  458.     //     $resultArr = [];
  459.     //     $resultArr1 = [];
  460.     //     foreach ($advanceCustomNotifications as $advanceCustomNotification) {
  461.     //         $finalResult = false;
  462.     //         $data = [];
  463.     //         $groupData = [];
  464.     //         $rules = $advanceCustomNotification->getNotificationConfig();
  465.     //         $groupConditions = [];
  466.     //         $ruleCondition = [];
  467.     //         $ruleValues = [];
  468.     //         $groupRuleCondition = [];
  469.     //         $groupRuleValues = [];
  470.     //         $groupValues = [];
  471.     //         $sequence = [];
  472.     //         if ($rules) {
  473.     //             foreach ($rules as $ruleConfig) {
  474.     //                 if ($ruleConfig->getRuleType() == 'rule') {
  475.     //                     if ($ruleConfig->getRulecondition() != null) {
  476.     //                         $ruleCondition[] = $ruleConfig->getRulecondition();
  477.     //                     }
  478.     //                     try {
  479.     //                         $result = $this->getMeteomaticData($ruleConfig, $startDate, $endDate);
  480.     //                         if (!empty($result)) {
  481.     //                             $data[] = $result;
  482.     //                             $ruleValues[] = true;
  483.     //                             $sequence[] = [
  484.     //                                 'name' => $ruleConfig->getName(),
  485.     //                                 'condition' => $ruleConfig->getRuleCondition(),
  486.     //                                 'type' => 'rule',
  487.     //                                 'value' => true
  488.     //                             ];
  489.     //                         } else {
  490.     //                             $ruleValues[] = false;
  491.     //                             $sequence[] = [
  492.     //                                 'name' => $ruleConfig->getName(),
  493.     //                                 'condition' => $ruleConfig->getRuleCondition(),
  494.     //                                 'type' => 'rule',
  495.     //                                 'value' => false
  496.     //                             ];
  497.     //                         }
  498.     //                         $alertName = $result['alertName'];
  499.     //                         $qualifiedLocations = $result['data']['data'][0]['coordinates'][0]['dates'];
  500.     //                         if (is_array($result) && isset($result['data']['data'][0]['parameter']) && $result['data']['data'][0]['parameter'] = $result['parameterKey']) {
  501.     //                             foreach ($qualifiedLocations as $key => $qualifiedLocation) {
  502.     //                                 if ($ruleConfig->getCondition() == "range") {
  503.     //                                     $value2 = [];
  504.     //                                     $value2[0] = $ruleConfig->getConditionValueMin();
  505.     //                                     $value2[1] = $ruleConfig->getConditionValueMax();
  506.     //                                 } else {
  507.     //                                     $value2 = $ruleConfig->getConditionValueMin();
  508.     //                                 }
  509.     //                                 $value = $qualifiedLocation['value'];
  510.     //                                 $resultArr[$qualifiedLocation["date"]][$alertName] = $qualifiedLocation;
  511.     //                                 if ($result['comparedValue']) {
  512.     //                                     $resultArr1[] = [
  513.     //                                         "type" => "rule",
  514.     //                                         'name' => $ruleConfig->getName(),
  515.     //                                         'rule_condition' => $ruleConfig->getRuleCondition(),
  516.     //                                         'advance_custom_notification_id' => $advanceCustomNotification->getId(),
  517.     //                                         "date" => $qualifiedLocation['date'],
  518.     //                                         "location_id" => $ruleConfig->getLocation()?->getId(),
  519.     //                                         "location_name" => $ruleConfig->getLocation()?->getName(),
  520.     //                                         "location_title" => $ruleConfig->getLocation()?->getTitle(),
  521.     //                                         "advance_custom_notification_title" => $advanceCustomNotification->getNotificationName("en"),
  522.     //                                         "parameter" => $ruleConfig->getParameter()->getParamName("en"),
  523.     //                                         "calculation_type" => $ruleConfig->getCondition(),
  524.     //                                         "calculation_type_label" => isset($calculateOption[$ruleConfig->getCondition()]) ? $calculateOption[$ruleConfig->getCondition()] : "",
  525.     //                                         "user_value" => $value2,
  526.     //                                         'received_value' => $value,
  527.     //                                         "matched" => true
  528.     //                                     ];
  529.     //                                 } else {
  530.     //                                     $resultArr1[] = [
  531.     //                                         "type" => "rule",
  532.     //                                         'name' => $ruleConfig->getName(),
  533.     //                                         'rule_condition' => $ruleConfig->getRuleCondition(),
  534.     //                                         'advance_custom_notification_id' => $advanceCustomNotification->getId(),
  535.     //                                         "date" => $qualifiedLocation['date'],
  536.     //                                         "location_id" => $ruleConfig->getLocation()->getId(),
  537.     //                                         "location_name" => $ruleConfig->getLocation()?->getName(),
  538.     //                                         "location_title" => $ruleConfig->getLocation()?->getTitle(),
  539.     //                                         "advance_custom_notification_title" => $advanceCustomNotification->getNotificationName("en"),
  540.     //                                         "parameter" => $ruleConfig->getParameter()->getParamName("en"),
  541.     //                                         "calculation_type" => $ruleConfig->getCondition(),
  542.     //                                         "calculation_type_label" => isset($calculateOption[$ruleConfig->getCondition()]) ? $calculateOption[$ruleConfig->getCondition()] : "",
  543.     //                                         "user_value" => $value2,
  544.     //                                         'received_value' => $value,
  545.     //                                         "matched" => false
  546.     //                                     ];
  547.     //                                 }
  548.     //                             }
  549.     //                         }
  550.     //                         if (!empty($result)) {
  551.     //                             $data[] = $result;
  552.     //                             $ruleValues[] = true;
  553.     //                             $sequence[] = [
  554.     //                                 'name' => $ruleConfig->getName(),
  555.     //                                 'condition' => $ruleConfig->getRuleCondition(),
  556.     //                                 'type' => 'rule',
  557.     //                                 'value' => true
  558.     //                             ];
  559.     //                         } else {
  560.     //                             $ruleValues[] = false;
  561.     //                             $sequence[] = [
  562.     //                                 'name' => $ruleConfig->getName(),
  563.     //                                 'condition' => $ruleConfig->getRuleCondition(),
  564.     //                                 'type' => 'rule',
  565.     //                                 'value' => false
  566.     //                             ];
  567.     //                         }
  568.     //                     } catch (\Exception $e) {
  569.     //                         $msg = $e->getMessage();
  570.     //                         // $output->write("<fg=red>$msg</>");
  571.     //                         continue;
  572.     //                         // return Command::FAILURE;
  573.     //                     }
  574.     //                 } else {
  575.     //                     if ($ruleConfig->getRulecondition() != null) {
  576.     //                         $groupRuleCondition[$ruleConfig->getName()][] = $ruleConfig->getRulecondition();
  577.     //                     }
  578.     //                     $groupConditions[$ruleConfig->getName()] = $ruleConfig->getGroupcondition();
  579.     //                     try {
  580.     //                         $result = $this->getMeteomaticData($ruleConfig, $startDate, $endDate);
  581.     //                         if (!empty($result)) {
  582.     //                             $groupData[$ruleConfig->getName()][] = $result;
  583.     //                             $groupRuleValues[$ruleConfig->getName()][] = true;
  584.     //                         } else {
  585.     //                             $groupRuleValues[$ruleConfig->getName()][] = false;
  586.     //                         }
  587.     //                         $alertName = $result['alertName'];
  588.     //                         $qualifiedLocations = $result['data']['data'][0]['coordinates'][0]['dates'];
  589.     //                         if (is_array($result) && isset($result['data']['data'][0]['parameter']) && $result['data']['data'][0]['parameter'] = $result['parameterKey']) {
  590.     //                             foreach ($qualifiedLocations as $key => $qualifiedLocation) {
  591.     //                                 if ($ruleConfig->getCondition() == "range") {
  592.     //                                     $value2 = [];
  593.     //                                     $value2[0] = $ruleConfig->getConditionValueMin();
  594.     //                                     $value2[1] = $ruleConfig->getConditionValueMax();
  595.     //                                 } else {
  596.     //                                     $value2 = $ruleConfig->getConditionValueMin();
  597.     //                                 }
  598.     //                                 $value = $qualifiedLocation['value'];
  599.     //                                 $resultArr[$qualifiedLocation["date"]][$alertName] = $qualifiedLocation;
  600.     //                                 if ($result['comparedValue']) {
  601.     //                                     $resultArr1[] = [
  602.     //                                         "type" => "Group",
  603.     //                                         'name' => $ruleConfig->getName(),
  604.     //                                         'rule_condition' => $ruleConfig->getRuleCondition(),
  605.     //                                         'group_condition' => $ruleConfig->getGroupCondition(),
  606.     //                                         'advance_custom_notification_id' => $advanceCustomNotification->getId(),
  607.     //                                         "date" => $qualifiedLocation['date'],
  608.     //                                         "location_id" => $ruleConfig->getLocation()?->getId(),
  609.     //                                         "location_name" => $ruleConfig->getLocation()?->getName(),
  610.     //                                         "location_title" => $ruleConfig->getLocation()?->getTitle(),
  611.     //                                         "advance_custom_notification_title" => $advanceCustomNotification->getNotificationName("en"),
  612.     //                                         "parameter" => $ruleConfig->getParameter()->getParamName("en"),
  613.     //                                         "calculation_type" => $ruleConfig->getCondition(),
  614.     //                                         "calculation_type_label" => isset($calculateOption[$ruleConfig->getCondition()]) ? $calculateOption[$ruleConfig->getCondition()] : "",
  615.     //                                         "user_value" => $value2,
  616.     //                                         'received_value' => $value,
  617.     //                                         "matched" => true
  618.     //                                     ];
  619.     //                                 } else {
  620.     //                                     $resultArr1[] = [
  621.     //                                         "type" => "Group",
  622.     //                                         'name' => $ruleConfig->getName(),
  623.     //                                         'rule_condition' => $ruleConfig->getRuleCondition(),
  624.     //                                         'group_condition' => $ruleConfig->getGroupCondition(),
  625.     //                                         'advance_custom_notification_id' => $advanceCustomNotification->getId(),
  626.     //                                         "date" => $qualifiedLocation['date'],
  627.     //                                         "location_id" => $ruleConfig->getLocation()->getId(),
  628.     //                                         "location_name" => $ruleConfig->getLocation()?->getName(),
  629.     //                                         "location_title" => $ruleConfig->getLocation()?->getTitle(),
  630.     //                                         "advance_custom_notification_title" => $advanceCustomNotification->getNotificationName("en"),
  631.     //                                         "parameter" => $ruleConfig->getParameter()->getParamName("en"),
  632.     //                                         "calculation_type" => $ruleConfig->getCondition(),
  633.     //                                         "calculation_type_label" => isset($calculateOption[$ruleConfig->getCondition()]) ? $calculateOption[$ruleConfig->getCondition()] : "",
  634.     //                                         "user_value" => $value2,
  635.     //                                         'received_value' => $value,
  636.     //                                         "matched" => false
  637.     //                                     ];
  638.     //                                 }
  639.     //                             }
  640.     //                         }
  641.     //                         if (!empty($result)) {
  642.     //                             $data[] = $result;
  643.     //                             $ruleValues[] = true;
  644.     //                             $sequence[] = [
  645.     //                                 'name' => $ruleConfig->getName(),
  646.     //                                 'condition' => $ruleConfig->getRuleCondition(),
  647.     //                                 'type' => 'rule',
  648.     //                                 'value' => true
  649.     //                             ];
  650.     //                         } else {
  651.     //                             $ruleValues[] = false;
  652.     //                             $sequence[] = [
  653.     //                                 'name' => $ruleConfig->getName(),
  654.     //                                 'condition' => $ruleConfig->getRuleCondition(),
  655.     //                                 'type' => 'rule',
  656.     //                                 'value' => false
  657.     //                             ];
  658.     //                         }
  659.     //                     } catch (\Exception $e) {
  660.     //                         $msg = $e->getMessage();
  661.     //                         // $output->write("<fg=red>$msg</>");
  662.     //                         continue;
  663.     //                         // return Command::FAILURE;
  664.     //                     }
  665.     //                 }
  666.     //             }
  667.     //         }
  668.     //         if ($groupRuleValues) {
  669.     //             foreach ($groupRuleValues as $group => $values) {
  670.     //                 if (isset($groupRuleCondition[$group])) {
  671.     //                     $result = \App\Lib\Utility::evaluateConditions($values, $groupRuleCondition[$group]);
  672.     //                     $groupValues[$group] = $result;
  673.     //                     $sequence[] = [
  674.     //                         'name' => $group,
  675.     //                         'condition' => $groupConditions[$group],
  676.     //                         'type' => 'group',
  677.     //                         'value' => $groupValues[$group]
  678.     //                     ];
  679.     //                     if ($result) {
  680.     //                         $data = array_merge($data, array_values($groupData[$group]));
  681.     //                     }
  682.     //                 } else {
  683.     //                     $groupValues[$group] = $values[0];
  684.     //                     $sequence[] = [
  685.     //                         'name' => $group,
  686.     //                         'condition' => $groupConditions[$group],
  687.     //                         'type' => 'group',
  688.     //                         'value' => $values[0]
  689.     //                     ];
  690.     //                     if ($values[0]) {
  691.     //                         foreach (array_values($groupData[$group]) as $dataArray) {
  692.     //                             foreach ($dataArray as $dateKey => $value) {
  693.     //                                 array_push($data, [$dateKey => $value]);
  694.     //                             }
  695.     //                         }
  696.     //                     }
  697.     //                 }
  698.     //             }
  699.     //         }
  700.     //         $result = !empty($sequence) ? $sequence[0]['value'] : null;
  701.     //         if (count($sequence) > 1) {
  702.     //             // Start from the second element since the first one has no preceding condition
  703.     //             for ($i = 1; $i < count($sequence); $i++) {
  704.     //                 $currentElement = $sequence[$i];
  705.     //                 switch ($currentElement['condition']) {
  706.     //                     case "AND":
  707.     //                         $result = $result && $currentElement['value'];
  708.     //                         break;
  709.     //                     case "OR":
  710.     //                         $result = $result || $currentElement['value'];
  711.     //                         break;
  712.     //                 }
  713.     //             }
  714.     //         }
  715.     //         if ($result) {
  716.     //             $finalResult = true;
  717.     //         } else {
  718.     //             $finalResult = false;
  719.     //         }
  720.     //     }
  721.     //     $rawArr = array_values($resultArr1);
  722.     //     $organizedData = [];
  723.     //     $matchedAlert = [];
  724.     //     foreach ($rawArr as $entry) {
  725.     //         $notification = $entry;
  726.     //         $notificationId = $notification['advance_custom_notification_id'];
  727.     //         $date = date("Y-m-d", strtotime($notification['date']));
  728.     //         $time = date("H:i", strtotime($notification['date']));
  729.     //         $day = date("D", strtotime($notification['date']));
  730.     //         if (!isset($matchedAlert[$date . $notificationId]) || $notification['matched'] == true) {
  731.     //             $matchedAlert[$date . $notificationId] = $notification['matched'];
  732.     //         }
  733.     //         // Initialize the main array element for this notification ID if not already done
  734.     //         if (!isset($organizedData[$notificationId])) {
  735.     //             $organizedData[$notificationId] = [
  736.     //                 "advance_custom_notification_id" => $notification['advance_custom_notification_id'],
  737.     //                 "advance_custom_notification_title" => $notification['advance_custom_notification_title'],
  738.     //                 // "location_title" => $notification['location_title'],
  739.     //                 "alerts" => [],
  740.     //                 "user_value" => $notification['user_value'], // Static value, change as needed
  741.     //                 "calculation_type" => $notification['calculation_type'],
  742.     //                 "calculation_type_label" => $notification['calculation_type_label'],
  743.     //                 "parameterName" => $notification['parameter'],
  744.     //                 'finalResult' =>  $finalResult
  745.     //             ];
  746.     //         }
  747.     //         // Initialize the date array element if not already done
  748.     //         if (!isset($organizedData[$notificationId]['alerts'][$date])) {
  749.     //             $organizedData[$notificationId]['alerts'][$date] = [
  750.     //                 'date' => $date,
  751.     //                 'day' => $day,
  752.     //                 'rawDate' => $notification['date'],
  753.     //                 'data' => []
  754.     //             ];
  755.     //         }
  756.     //         $organizedData[$notificationId]['alerts'][$date]["isAlertPresent"] = $matchedAlert[$date . $notificationId];
  757.     //         // Append time data to the corresponding date
  758.     //         $organizedData[$notificationId]['alerts'][$date]['data'][] = [
  759.     //             'fromInterval' => $notification['date'],
  760.     //             'toInterval' => $notification['date'],
  761.     //             'data' => $notification,
  762.     //         ];
  763.     //     }
  764.     //     return ["success" => true, "data" => array_values($organizedData)];
  765.     // }
  766.     //     public function getAdvanceCalendarNotification(MeteomaticsWeatherService $mateoMaticsService, $user, $advanceCustomNotificationIds, $startDate, $endDate, $hour, $page, $size, $title, $paginator, $translator): array
  767.     // {
  768.     //     $qualifiedLocations = [];
  769.     //     $advanceCustomNotifications = new DataObject\AdvanceCustomNotification\Listing();
  770.     //     $advanceCustomNotifications->addConditionParam('o_id IN (' . $advanceCustomNotificationIds . ')');
  771.     //     $advanceCustomNotifications->filterByUser($user);
  772.     //     $advanceCustomNotifications->setOrderKey("o_id");
  773.     //     $advanceCustomNotifications->setOrder("desc");
  774.     //     if (!empty($title)) {
  775.     //         $advanceCustomNotifications->addConditionParam("notificationName like '%$title%' ");
  776.     //     }
  777.     //     $totalAdvanceCustomNotifications = $advanceCustomNotifications->count();
  778.     //     if (!$totalAdvanceCustomNotifications) {
  779.     //         return ['success' => false, 'message' => $translator->trans("you_do_not_have_any_advance_custom_notification_configured")];
  780.     //     }
  781.     //     $resultArr1 = [];
  782.     //     foreach ($advanceCustomNotifications as $advanceCustomNotification) {
  783.     //         $rules = $advanceCustomNotification->getNotificationConfig();
  784.     //         $ruleDates = [];
  785.     //         if ($rules) {
  786.     //             $data = [];
  787.     //             $ruleDates = [];
  788.     //             foreach ($rules as $ruleConfig) {
  789.     //                 $ruleId = $ruleConfig->getName() . '-' . $ruleConfig->getLocation()?->getName('en') . '-' . $ruleConfig->getParameter()?->getParamName("en") . '-' . $ruleConfig->getCondition();
  790.     //                 $ruleDetails = [
  791.     //                                     'ruleId' => $ruleId,
  792.     //                                     'ruleName' => $ruleConfig->getName(),
  793.     //                                     'ruleType' => $ruleConfig->getRuleType(),
  794.     //                                     'location' => $ruleConfig->getLocation()?->getName('en'),
  795.     //                                     'model' => $ruleConfig->getModelParam(),
  796.     //                                     'parameter' => $ruleConfig->getParameter()?->getParamName("en"),
  797.     //                                     'parameterKey' => $ruleConfig->getParameter()?->getParamKey(),
  798.     //                                     'timeInterval' => $ruleConfig->getTimeInterval(),
  799.     //                                     'condition' => $ruleConfig->getCondition(),
  800.     //                                     'conditionValueMax' => $ruleConfig->getConditionValueMax(),
  801.     //                                     'conditionValueMin' => $ruleConfig->getConditionValueMin(),
  802.     //                                 ];
  803.     //                                 $data[] = $ruleDetails;
  804.     //             }
  805.     //             return ["success" => true, "data" => $data];
  806.     //         }
  807.     //     }
  808.     //     return ["success" => true, "data" => $resultArr1];
  809.     // }
  810.     /**
  811.      * The main function that fetches, paginates, and processes notifications.
  812.      */
  813.     public function getAdvanceCalendarNotification(
  814.         MeteomaticsWeatherService $mateoMaticsService,
  815.         $user,
  816.         $advanceCustomNotificationIds,
  817.         $startDate,
  818.         $endDate,
  819.         $hour,
  820.         $page,
  821.         $size,
  822.         $title,
  823.         $paginator,
  824.         $translator,
  825.         $location '',
  826.         $locationTagName
  827.     ): array {
  828.         // -----------------------------------------------------------
  829.         // 1) Basic validations
  830.         // -----------------------------------------------------------
  831.         if (empty($advanceCustomNotificationIds)) {
  832.             return [
  833.                 'success' => false,
  834.                 'message' => $translator->trans("you_do_not_have_any_advance_custom_notification_configured")
  835.             ];
  836.         }
  837.         // We use Asia/Riyadh as per your requirement
  838.         $timezone = new DateTimeZone("Asia/Riyadh");
  839.         $startDateObj = new DateTime($startDate$timezone);
  840.         $endDateObj   = new DateTime($endDate$timezone);
  841.         // -----------------------------------------------------------
  842.         // 2) Build the DataObject query
  843.         // -----------------------------------------------------------
  844.         $advanceCustomNotifications = new DataObject\AdvanceCustomNotification\Listing();
  845.         $advanceCustomNotifications->addConditionParam('o_id IN (' $advanceCustomNotificationIds ')');
  846.         // Only those owned by the user or shared with them
  847.         $advanceCustomNotifications->addConditionParam(
  848.             'owner__id = ? OR user LIKE ?',
  849.             [$user->getId(), '%,' $user->getId() . ',%']
  850.         );
  851.         // Optional: Filter by title
  852.         if (!empty($title)) {
  853.             $advanceCustomNotifications->addConditionParam("notificationName like '%$title%' ");
  854.         }
  855.         // Optional: Filter by location Tag Name
  856.         if (!empty($locationTagName)) {
  857.             $db \Pimcore\Db::get();
  858.             $tagIds $db->fetchFirstColumn(
  859.                 "SELECT ooo_id
  860.                  FROM object_localized_data_Tags
  861.                  WHERE language = :language AND TagName LIKE :tagName",
  862.                 [
  863.                     'language' => $translator->getLocale(),
  864.                     'tagName'  => '%' $locationTagName '%'
  865.                 ]
  866.             );
  867.             if (!empty($tagIds)) {
  868.                 $condition 'locationTag__id IN (' implode(","$tagIds) . ')';
  869.                 $advanceCustomNotifications->addConditionParam($condition);
  870.             } 
  871.         }
  872.          // Optional: Filter by location
  873.          if (!empty($location)) {
  874.             $advanceCustomNotifications->addConditionParam("locationNames like '%$location%' ");
  875.         }
  876.         // Sorting
  877.         $advanceCustomNotifications->setOrderKey("o_id");
  878.         $advanceCustomNotifications->setOrder("desc");
  879.         $totalAdvanceCustomNotifications $advanceCustomNotifications->count();
  880.         if (!$totalAdvanceCustomNotifications) {
  881.             return [
  882.                 'success' => false,
  883.                 'message' => $translator->trans("you_do_not_have_any_advance_custom_notification_configured")
  884.             ];
  885.         }
  886.         // -----------------------------------------------------------
  887.         // 3) Pagination
  888.         // -----------------------------------------------------------
  889.         $pageSize  $size ?? LIMIT_PER_PAGE;  // Adjust to your default
  890.         $page      $page ?? 1;
  891.         $paginator $paginator->paginate($advanceCustomNotifications$page$pageSize);
  892.         // -----------------------------------------------------------
  893.         // 4) Main loop over notifications
  894.         // -----------------------------------------------------------
  895.         $alertsData = [];
  896.         foreach ($paginator as $advanceCustomNotification) {
  897.             $rules $advanceCustomNotification->getNotificationConfig();
  898.             if (!$rules) {
  899.                 // No rules, skip
  900.                 continue;
  901.             }
  902.             // We'll accumulate day-based data:
  903.             $ruleDates = [];
  904.             // We'll also keep a sequence of T/F for each rule/group for top-level combination (AND/OR).
  905.             $sequence  = [];
  906.             // Handling groups
  907.             $groupRuleValues    = [];  // groupName => [bool, bool, ...]
  908.             $groupRuleCondition = [];  // groupName => e.g. ['AND','OR',...]
  909.             $groupConditions    = [];  // groupName => 'AND' or 'OR'
  910.             $groupArr           = [];
  911.             $ruleIndex  1;
  912.             $groupIndex 0;
  913.             // ---------------------------------------------
  914.             // 4a) Process each rule in the notification
  915.             // ---------------------------------------------
  916.             foreach ($rules as $key => $ruleConfig) {
  917.                 $name 'Rule' $ruleIndex;
  918.                 // Call YOUR getMeteomaticData
  919.                 // We pass in the same $timezone used above
  920.                 try {
  921.                     $result $this->getMeteomaticData($ruleConfig$startDateObj$endDateObj$timezone);
  922.                 } catch (Exception $e) {
  923.                     // Handle/log error
  924.                     continue;
  925.                 }
  926.                 // If 'comparedValue' is not empty => that means the condition was matched at some level
  927.                 // (per your custom compareValueofCustomNotification logic).
  928.                 $isMatched = !empty($result['comparedValue']);
  929.                 // Distinguish single rule vs. group
  930.                 if ($ruleConfig->getRuleType() === 'group') {
  931.                     $groupIndex++;
  932.                     if ($ruleConfig->getRulecondition() != null) {
  933.                         $groupRuleCondition[$ruleConfig->getName()][] = $ruleConfig->getRulecondition();
  934.                     }
  935.                     $groupArr[] = $ruleConfig->getName();
  936.                     $groupConditions[$ruleConfig->getName()] = $ruleConfig->getGroupCondition();
  937.                     // Store the sub-rule’s boolean
  938.                     $groupRuleValues[$ruleConfig->getName()][] = $isMatched;
  939.                 } else {
  940.                     $ruleIndex++;
  941.                     // Add a top-level entry for single rule
  942.                     $sequence[] = [
  943.                         'name'      => $ruleConfig->getName(),
  944.                         'condition' => $ruleConfig->getRuleCondition(),
  945.                         'type'      => 'rule',
  946.                         'value'     => $isMatched
  947.                     ];
  948.                 }
  949.                 // --------------------------------------------------
  950.                 // Build day-by-day intervals from the returned data
  951.                 // --------------------------------------------------
  952.                 $datesData $result['data']['data'][0]['coordinates'][0]['dates'] ?? [];
  953.                 $ruleId    $this->generateRuleId($ruleConfig$key);
  954.                 $intervalsPerDay $this->buildDayIntervals($datesData$ruleConfig);
  955.                 // Insert these intervals into $ruleDates
  956.                 foreach ($intervalsPerDay as $day => $intervals) {
  957.                     if (!isset($ruleDates[$day])) {
  958.                         $ruleDates[$day] = [];
  959.                     }
  960.                     // Build a standard data structure about this rule
  961.                     $ruleDetails = [
  962.                         'ruleIndex'  => ($ruleConfig->getRuleType() === 'group') ? $groupIndex $ruleIndex,
  963.                         'name'       => ($ruleConfig->getRuleType() === 'group')
  964.                             ? "Rule{$groupIndex}"
  965.                             $name,
  966.                         'ruleName'   => $ruleConfig->getName(),
  967.                         'advanceCustomNotificationTitle' => $advanceCustomNotification->getNotificationName('en'),
  968.                         'ruleId'     => $ruleId,
  969.                         'ruleType'   => $ruleConfig->getRuleType(),
  970.                         'location'   => $ruleConfig->getLocation()?->getTitle('en'),
  971.                         'severity_code' => (
  972.                             \App\Lib\Utility::getSeverityCode($advanceCustomNotification->getSeverity(), CUSTOM_NOTIFICATION_CONFIG_COLORS)
  973.                             ?: ''
  974.                         ),
  975.                         'severity'       => $advanceCustomNotification->getSeverity(),
  976.                         'severityAr'     => (
  977.                             \App\Lib\Utility::getArabicTranslation($advanceCustomNotification->getSeverity(), CUSTOM_NOTIFICATION_CONFIG_COLORS)
  978.                             ?: ''
  979.                         ),
  980.                         'model'          => $ruleConfig->getModelParam(),
  981.                         'modelEn'        => (
  982.                             \App\Lib\Utility::getArabicTranslationByKey('value'$ruleConfig->getModelParam(), CUSTOM_NOTIFICATION_MODEL_TYPE'en')
  983.                             ?: ''
  984.                         ),
  985.                         'modelAr'        => (
  986.                             \App\Lib\Utility::getArabicTranslationByKey('value'$ruleConfig->getModelParam(), CUSTOM_NOTIFICATION_MODEL_TYPE'ar')
  987.                             ?: ''
  988.                         ),
  989.                         'unit'            => $ruleConfig->getParameterUnitKey(),
  990.                         'unitAr'          => \App\Lib\Utility::getArabicTranslationUnits($ruleConfig->getParameterUnitKey()),
  991.                         'parameterKey'    => $ruleConfig->getParameter()?->getParamKey(),
  992.                         'parameter'       => $ruleConfig->getParameter()?->getParamName('en'),
  993.                         'parameterAr'     => $ruleConfig->getParameter()?->getParamName('ar'),
  994.                         'condition'       => $ruleConfig->getCondition(),
  995.                         'conditionAr'     => (
  996.                             \App\Lib\Utility::getArabicTranslation($ruleConfig->getCondition(), CUSTOM_NOTIFICATION_CONDITION)
  997.                             ?: ''
  998.                         ),
  999.                         'timeInterval'    => $ruleConfig->getTimeInterval(),
  1000.                         'conditionValueMax' => $ruleConfig->getConditionValueMax(),
  1001.                         'conditionValueMin' => $ruleConfig->getConditionValueMin(),
  1002.                         'timeInDays'      => $ruleConfig->getTimeInDays(),
  1003.                         'ruleCondition'   => $ruleConfig->getRuleCondition(),
  1004.                         'groupCondition'  => $ruleConfig->getGroupCondition(),
  1005.                         'modelValue'      => $ruleConfig->getModelValue(),
  1006.                         'heightOrDepth'   => $ruleConfig->getHeightOrDepth(),
  1007.                         'rawDate'         => isset($intervals[0]) ? $intervals[0]['time'] : null,
  1008.                         'intervals'       => $intervals
  1009.                     ];
  1010.                     // If it's a group rule, nest it inside a group array
  1011.                     if ($ruleConfig->getRuleType() === 'group') {
  1012.                         $groupExists false;
  1013.                         foreach ($ruleDates[$day] as &$existingGroup) {
  1014.                             if (isset($existingGroup['groupName']) && $existingGroup['groupName'] === $ruleConfig->getName()) {
  1015.                                 $existingGroup['rules'][] = $ruleDetails;
  1016.                                 $groupExists true;
  1017.                                 break;
  1018.                             }
  1019.                         }
  1020.                         if (!$groupExists) {
  1021.                             $ruleDates[$day][] = [
  1022.                                 'groupName' => $ruleConfig->getName(),
  1023.                                 'rules'     => [$ruleDetails],
  1024.                             ];
  1025.                         }
  1026.                     } else {
  1027.                         // It's a normal rule
  1028.                         $ruleExists false;
  1029.                         foreach ($ruleDates[$day] as &$existingRuleData) {
  1030.                             if (isset($existingRuleData['ruleId']) && $existingRuleData['ruleId'] === $ruleId) {
  1031.                                 $existingRuleData['intervals'] = array_merge($existingRuleData['intervals'], $intervals);
  1032.                                 $ruleExists true;
  1033.                                 break;
  1034.                             }
  1035.                         }
  1036.                         if (!$ruleExists) {
  1037.                             $ruleDates[$day][] = $ruleDetails;
  1038.                         }
  1039.                     }
  1040.                 }
  1041.             } // end foreach $rules
  1042.             // ---------------------------------------------
  1043.             // 4b) Evaluate group booleans & push to $sequence
  1044.             // ---------------------------------------------
  1045.             if (!empty($groupRuleValues)) {
  1046.                 foreach ($groupRuleValues as $groupName => $values) {
  1047.                     if (isset($groupRuleCondition[$groupName])) {
  1048.                         // Evaluate using your custom group logic
  1049.                         $wholeGroupResult \App\Lib\Utility::evaluateConditions(
  1050.                             $values,
  1051.                             $groupRuleCondition[$groupName]
  1052.                         );
  1053.                         $sequence[] = [
  1054.                             'name'      => $groupName,
  1055.                             'condition' => $groupConditions[$groupName] ?? null,
  1056.                             'type'      => 'group',
  1057.                             'value'     => $wholeGroupResult
  1058.                         ];
  1059.                     } else {
  1060.                         // No explicit condition set => just take the first
  1061.                         $sequence[] = [
  1062.                             'name'      => $groupName,
  1063.                             'condition' => $groupConditions[$groupName] ?? null,
  1064.                             'type'      => 'group',
  1065.                             'value'     => $values[0]
  1066.                         ];
  1067.                     }
  1068.                 }
  1069.             }
  1070.             // ---------------------------------------------
  1071.             // 4c) Combine top-level booleans with AND/OR
  1072.             // ---------------------------------------------
  1073.             $finalRuleOrGroupResult $this->evaluateSequence($sequence);
  1074.             // ---------------------------------------------
  1075.             // 4d) Build final day-based array
  1076.             // ---------------------------------------------
  1077.             $daysData = [];
  1078.             foreach ($ruleDates as $day => $rulesOnDay) {
  1079.                 // Check if ANY interval is matched => finalResult = true
  1080.                 $dayHasMatched $this->hasAnyMatched($rulesOnDay);
  1081.                 // If you need to combine with $finalRuleOrGroupResult, do so here, e.g.:
  1082.                 // $final = $dayHasMatched && $finalRuleOrGroupResult;
  1083.                 // For now, we'll just rely on "any match" => true
  1084.                 $daysData[] = [
  1085.                     'finalResult' => $dayHasMatched,
  1086.                     'date'        => $day,
  1087.                     'data'        => $rulesOnDay
  1088.                 ];
  1089.             }
  1090.             // Add this notification's days to $alertsData
  1091.             $alertsData[] = $daysData;
  1092.         }
  1093.         // -----------------------------------------------------------
  1094.         // 5) Return data + pagination variables
  1095.         // -----------------------------------------------------------
  1096.         return [
  1097.             'success'             => true,
  1098.             'data'                => $alertsData,
  1099.             'paginationVariables' => $paginator->getPaginationData()
  1100.         ];
  1101.     }
  1102.     /**
  1103.      * YOUR real getMeteomaticData() method (replaces the placeholder).
  1104.      */
  1105.     public function getMeteomaticData($rule$startDate$endDate$timezone null)
  1106.     {
  1107.         if (empty($startDate) || empty($endDate)) {
  1108.             throw new \InvalidArgumentException('Invalid dates');
  1109.         }
  1110.         // Just reuse your code as-is; below is copied from your snippet:
  1111.         $startDateObj $startDate;
  1112.         $endDateObj   $endDate;
  1113.         if ($timezone) {
  1114.             $startDateUtc $startDateObj->setTimezone($timezone)->format('Y-m-d\TH:i:s.v\Z');
  1115.             $endDateUtc   $endDateObj->setTimezone($timezone)->format('Y-m-d\TH:i:s.v\Z');
  1116.         } else {
  1117.             $startDateUtc $startDateObj->setTimezone(new DateTimeZone('UTC'))->format('Y-m-d\TH:i:s.v\Z');
  1118.             $endDateUtc   $endDateObj->setTimezone(new DateTimeZone('UTC'))->format('Y-m-d\TH:i:s.v\Z');
  1119.         }
  1120.         // Rule parameters
  1121.         $duration $rule->getTimeInterval();
  1122.         $param    $rule->getParameter()->getParamKey();
  1123.         $paramName $rule->getParameter()->getParamName("en");
  1124.         $unit     $rule->getParameterUnitKey();
  1125.         $coordinates json_decode($rule->getLocation()->getCoordinates(), true);
  1126.         $heightDepth $rule->getHeightOrDepth();
  1127.         $durationInterval 1;
  1128.         if (stripos($rule->getTimeInDays(), 'h') !== false) {
  1129.             $hours = (int) filter_var($rule->getTimeInDays(), FILTER_SANITIZE_NUMBER_INT);
  1130.             $durationInterval $hours;                
  1131.         } else {
  1132.             $days = (int) filter_var($rule->getTimeInDays(), FILTER_SANITIZE_NUMBER_INT);
  1133.             $durationInterval $days 24
  1134.         }
  1135.         if ($durationInterval==0) {
  1136.             $durationInterval=24;
  1137.         }
  1138.         // $resolution  = 'PT'.$durationInterval.'H';
  1139.         $resolution  'PT1H'// Hourly resolution
  1140.         $model       $rule->getModelParam() !== "model"
  1141.             "mix&calibrated=true"
  1142.             : ($rule->getModelValue() ?: 'mix');
  1143.         // Build parameter string
  1144.         $parametersStr $param;
  1145.         if ($heightDepth) {
  1146.             $parametersStr .= '_' $heightDepth;
  1147.         }
  1148.         if ($duration) {
  1149.             $parametersStr .= '_' $duration 'h';
  1150.         }
  1151.         if ($unit) {
  1152.             $parametersStr .= ':' $unit;
  1153.         }
  1154.         // Format coordinates
  1155.         $formattedCoordinates = (count($coordinates) > 1)
  1156.             ? implode('+'array_map(fn($coord) => implode(','$coord), $coordinates))
  1157.             : implode(','$coordinates[0]);
  1158.         // Construct API URL
  1159.         $url "{$this->apiBaseUrl}/{$startDateUtc}--{$endDateUtc}:{$resolution}/{$parametersStr}/{$formattedCoordinates}/json?source={$model}&use_decluttered=true";
  1160.         // Make API request via Guzzle
  1161.         $client   = new Client(['verify' => false]);
  1162.         $response $client->request('GET'$url, [
  1163.             'auth' => [$this->username$this->password],
  1164.         ]);
  1165.         $data json_decode($response->getBody(), true);
  1166.         // Compare values using your existing utility method
  1167.         $ruleValue \App\Lib\Utility::compareValueofCustomNotification(
  1168.             $data,
  1169.             $rule->getCondition(),
  1170.             $rule->getConditionValueMin(),
  1171.             $rule->getConditionValueMax(),
  1172.             $paramName,
  1173.             $rule->getLocation()->getName(),
  1174.             $unit
  1175.         );
  1176.         return [
  1177.             "data"          => $data,
  1178.             'comparedValue' => $ruleValue,
  1179.             "parameterKey"  => $parametersStr,
  1180.             'alertName'     => $paramName
  1181.         ];
  1182.     }
  1183.     /**
  1184.      * Break down the 'dates' array from Meteomatics into day-based intervals.
  1185.      */
  1186.     private function buildDayIntervals(array $datesData$ruleConfig): array
  1187.     {
  1188.         $intervalsPerDay = [];
  1189.         foreach ($datesData as $date) {
  1190.             if (!isset($date['date']) || !isset($date['value'])) {
  1191.                 continue;
  1192.             }
  1193.             $time  $date['date'];
  1194.             $value $date['value'];
  1195.             $day   = (new DateTime($time))->format('Y-m-d');
  1196.             if (!isset($intervalsPerDay[$day])) {
  1197.                 $intervalsPerDay[$day] = [];
  1198.             }
  1199.             // Evaluate 'matched' for each hourly interval
  1200.             $matched \App\Lib\Utility::isWeatherConditionMatched(
  1201.                 $ruleConfig->getConditionValueMin(),
  1202.                 $ruleConfig->getConditionValueMax(),
  1203.                 $value,
  1204.                 $ruleConfig->getCondition()
  1205.             );
  1206.             $intervalsPerDay[$day][] = [
  1207.                 'time'              => $time,
  1208.                 'value'             => $value,
  1209.                 'condition'         => $ruleConfig->getCondition(),
  1210.                 'conditionValueMax' => $ruleConfig->getConditionValueMax(),
  1211.                 'conditionValueMin' => $ruleConfig->getConditionValueMin(),
  1212.                 'matched'           => $matched,
  1213.             ];
  1214.         }
  1215.         return $intervalsPerDay;
  1216.     }
  1217.     /**
  1218.      * Combine an array of booleans with AND/OR logic in sequence order.
  1219.      */
  1220.     private function evaluateSequence(array $sequence): bool
  1221.     {
  1222.         if (empty($sequence)) {
  1223.             return false;
  1224.         }
  1225.         $final $sequence[0]['value'];
  1226.         for ($i 1$i count($sequence); $i++) {
  1227.             $current $sequence[$i];
  1228.             switch ($current['condition']) {
  1229.                 case 'AND':
  1230.                     $final $final && $current['value'];
  1231.                     break;
  1232.                 case 'OR':
  1233.                     $final $final || $current['value'];
  1234.                     break;
  1235.                 default:
  1236.                     // fallback or handle unknown
  1237.                     $final $final && $current['value'];
  1238.             }
  1239.         }
  1240.         return $final;
  1241.     }
  1242.     /**
  1243.      * Determine if ANY interval in the day's data was matched.
  1244.      * Supports both single-rule arrays and grouped rules.
  1245.      */
  1246.     private function hasAnyMatched(array $rulesOnDay): bool
  1247.     {
  1248.         foreach ($rulesOnDay as $ruleData) {
  1249.             // If it's a group => check $ruleData['rules']
  1250.             if (isset($ruleData['groupName']) && isset($ruleData['rules'])) {
  1251.                 foreach ($ruleData['rules'] as $subRule) {
  1252.                     foreach ($subRule['intervals'] as $interval) {
  1253.                         if (!empty($interval['matched'])) {
  1254.                             return true;
  1255.                         }
  1256.                     }
  1257.                 }
  1258.             } else {
  1259.                 // Single rule => intervals are directly in $ruleData['intervals']
  1260.                 if (isset($ruleData['intervals'])) {
  1261.                     foreach ($ruleData['intervals'] as $interval) {
  1262.                         if (!empty($interval['matched'])) {
  1263.                             return true;
  1264.                         }
  1265.                     }
  1266.                 }
  1267.             }
  1268.         }
  1269.         return false;
  1270.     }
  1271.     /**
  1272.      * Generate a unique rule ID (mimicking your original approach).
  1273.      */
  1274.     private function generateRuleId($ruleConfig$key): string
  1275.     {
  1276.         $locName   $ruleConfig->getLocation()?->getName('en') ?? '';
  1277.         $paramName $ruleConfig->getParameter()?->getParamName('en') ?? '';
  1278.         return sprintf(
  1279.             "%s-%s-%s-%s-%d",
  1280.             $ruleConfig->getName(),
  1281.             $locName,
  1282.             $paramName,
  1283.             $ruleConfig->getCondition(),
  1284.             $key
  1285.         );
  1286.     }
  1287.     public function getAdvanceNotifications(
  1288.         MeteomaticsWeatherService $mateoMaticsService,
  1289.         $user,
  1290.         $notificationIds,
  1291.         $startDate,
  1292.         $endDate,
  1293.         $hour,
  1294.         $page,
  1295.         $size,
  1296.         $title,
  1297.         $paginator,
  1298.         $translator
  1299.     ): array {
  1300.         $timezone = new \DateTimeZone("Asia/Riyadh");
  1301.         $startDateObj = new \DateTime($startDate$timezone);
  1302.         $endDateObj = new \DateTime($endDate$timezone);
  1303.         $pageSize = isset($size) ? $size LIMIT_PER_PAGE;
  1304.         $page = isset($page) ? $page 1;
  1305.         if (empty($notificationIds)) {
  1306.             return ['success' => false'message' => $translator->trans("no_notifications_configured")];
  1307.         }
  1308.         $notificationListing = new DataObject\AdvanceCustomNotification\Listing();
  1309.         $notificationListing->addConditionParam('o_id IN (' $notificationIds ')');
  1310.         $notificationListing->addConditionParam('owner__id = ? OR user LIKE ? ', [$user->getId(), '%,' $user->getId() . ',%']);
  1311.         $notificationListing->setOrderKey("o_id");
  1312.         $notificationListing->setOrder("desc");
  1313.         if (!empty($title)) {
  1314.             $notificationListing->addConditionParam("notificationName like '%$title%' ");
  1315.         }
  1316.         if (!empty($location)) {
  1317.             $db \Pimcore\Db::get();
  1318.             $tagIds $db->fetchFirstColumn(
  1319.                 "SELECT ooo_id 
  1320.                 FROM object_localized_data_Tags
  1321.                 WHERE language = :language AND TagName LIKE :tagName",
  1322.                 [
  1323.                     'language' => $translator->getLocale(),
  1324.                     'tagName' => '%' $location '%'
  1325.                 ]
  1326.             );
  1327.             if (!empty($tagIds)) {
  1328.                 $condition 'locationTag__id IN (' implode(","$tagIds) . ') OR locationNames LIKE ?';
  1329.                 $params = [
  1330.                     '%' $location '%',
  1331.                 ];
  1332.                 $notificationListing->addConditionParam($condition$params);
  1333.             } else {
  1334.                 $notificationListing->addConditionParam("locationNames like '%$location%' ");
  1335.             }
  1336.         }
  1337.         $paginator $paginator->paginate(
  1338.             $notificationListing,
  1339.             $page,
  1340.             $pageSize
  1341.         );
  1342.         $notificationsCount $paginator->count();
  1343.         if (!$notificationsCount) {
  1344.             return ['success' => false'message' => $translator->trans("no_notifications_found")];
  1345.         }
  1346.         $resultArr = [];
  1347.         $matchedNotifications = [];
  1348.         foreach ($paginator as $notification) {
  1349.             // print($notification->getid());
  1350.             $rules $notification->getNotificationConfig();
  1351.             $notificationResult $this->processRules($rules$notification$startDateObj$endDateObj$hour$timezone);
  1352.         }
  1353.         return $notificationResult;
  1354.     }
  1355.     private function processRules(
  1356.         $rules,
  1357.         $notification,
  1358.         $startDateObj,
  1359.         $endDateObj,
  1360.         $hour,
  1361.         $timezone
  1362.     ): array {
  1363.         $data = [];
  1364.         $finalResult false// Overall final result for the notification
  1365.         $groupResults = [];
  1366.         $ruleIndex 1// Incremental index for rules
  1367.         foreach ($rules as $rule) {
  1368.             $ruleName $rule->getName();
  1369.             $ruleType $rule->getRuleType();
  1370.             $ruleCondition $rule->getRuleCondition();
  1371.             $groupCondition $rule->getGroupCondition();
  1372.             // Fetch Meteomatics data
  1373.             $result $this->getMeteomaticData($rule$startDateObj$endDateObj$timezone);
  1374.             $datesData $result['data']['data'][0]['coordinates'][0]['dates'];
  1375.             $intervalsPerDay = [];
  1376.             $isMatched false// Whether any interval matches the condition
  1377.             foreach ($datesData as $date) {
  1378.                 if (isset($date['date'], $date['value'])) {
  1379.                     $interval = [
  1380.                         'time' => $date['date'],
  1381.                         'value' => $date['value'],
  1382.                         'condition' => $rule->getCondition(),
  1383.                         'conditionValueMax' => $rule->getConditionValueMax(),
  1384.                         'conditionValueMin' => $rule->getConditionValueMin(),
  1385.                         'matched' => \App\Lib\Utility::compareValues(
  1386.                             $rule->getCondition(),
  1387.                             $date['value'],
  1388.                             [
  1389.                                 $rule->getConditionValueMin(),
  1390.                                 $rule->getConditionValueMax(),
  1391.                             ]
  1392.                         ),
  1393.                     ];
  1394.                     $day = (new DateTime($date['date']))->format('Y-m-d');
  1395.                     if (!isset($intervalsPerDay[$day])) {
  1396.                         $intervalsPerDay[$day] = [];
  1397.                     }
  1398.                     $intervalsPerDay[$day][] = $interval;
  1399.                     // Check if any interval matches
  1400.                     if ($interval['matched']) {
  1401.                         $isMatched true;
  1402.                     }
  1403.                 }
  1404.             }
  1405.             foreach ($intervalsPerDay as $day => $intervals) {
  1406.                 $ruleDetails = [
  1407.                     'alertId' => $notification->getID(),
  1408.                     'ruleIndex' => $ruleIndex,
  1409.                     'name' => $ruleType === 'group' "Group" "Rule" $ruleIndex,
  1410.                     'ruleName' => $ruleName,
  1411.                     'advanceCustomNotificationTitle' => $notification->getNotificationName('en'),
  1412.                     'ruleId' => $ruleName '-' $rule->getLocation()?->getName('en'),
  1413.                     'ruleType' => $ruleType,
  1414.                     'location' => $rule->getLocation()?->getName('en'),
  1415.                     'severity_code' => (\App\Lib\Utility::getSeverityCode($notification->getSeverity(), CUSTOM_NOTIFICATION_CONFIG_COLORS) ? \App\Lib\Utility::getSeverityCode($notification->getSeverity(), CUSTOM_NOTIFICATION_CONFIG_COLORS) : ''),
  1416.                     'severity' => $notification->getSeverity(),
  1417.                     'severityAr' => (\App\Lib\Utility::getArabicTranslation($notification->getSeverity(), CUSTOM_NOTIFICATION_CONFIG_COLORS) ? \App\Lib\Utility::getArabicTranslation($notification->getSeverity(), CUSTOM_NOTIFICATION_CONFIG_COLORS) : ''),
  1418.                     'model' => $rule->getModelParam(),
  1419.                     'modelEn' => (\App\Lib\Utility::getArabicTranslationByKey('value'$rule->getModelParam(), CUSTOM_NOTIFICATION_MODEL_TYPE'en') ? \App\Lib\Utility::getArabicTranslationByKey('value'$rule->getModelParam(), CUSTOM_NOTIFICATION_MODEL_TYPE'en') : ''),
  1420.                     'modelAr' => (\App\Lib\Utility::getArabicTranslationByKey('value'$rule->getModelParam(), CUSTOM_NOTIFICATION_MODEL_TYPE'ar') ? \App\Lib\Utility::getArabicTranslationByKey('value'$rule->getModelParam(), CUSTOM_NOTIFICATION_MODEL_TYPE'ar') : ''),
  1421.                     'unit' => $rule->getParameterUnitKey(),
  1422.                     'unitAr' => (\App\Lib\Utility::getArabicTranslationUnits($rule->getParameterUnitKey())),
  1423.                     'parameterKey' => $rule->getParameter()?->getParamKey(),
  1424.                     'parameter' => $rule->getParameter()?->getParamName('en'),
  1425.                     'parameterAr' => $rule->getParameter()?->getParamName('ar'),
  1426.                     'condition' => $rule->getCondition(),
  1427.                     'conditionAr' => (\App\Lib\Utility::getArabicTranslation($rule->getCondition(), CUSTOM_NOTIFICATION_CONDITION) ? \App\Lib\Utility::getArabicTranslation($rule->getCondition(), CUSTOM_NOTIFICATION_CONDITION) : ''),
  1428.                     'timeInterval' => $rule->getTimeInterval(),
  1429.                     'conditionValueMax' => $rule->getConditionValueMax(),
  1430.                     'conditionValueMin' => $rule->getConditionValueMin(),
  1431.                     'timeInDays' => $rule->getTimeInDays(),
  1432.                     'ruleCondition' => $rule->getRuleCondition(),
  1433.                     'groupCondition' => $rule->getGroupCondition(),
  1434.                     'modelValue' => $rule->getModelValue(),
  1435.                     'heightOrDepth' => $rule->getHeightOrDepth(),
  1436.                     'rawDate' => $intervals[0]['time'],
  1437.                     'intervals' => $intervals,
  1438.                 ];
  1439.                 if ($ruleType === 'group') {
  1440.                     // Aggregate group results
  1441.                     if (!isset($groupResults[$ruleName])) {
  1442.                         $groupResults[$ruleName] = [
  1443.                             'rules' => [],
  1444.                             'condition' => $groupCondition,
  1445.                             'values' => [],
  1446.                         ];
  1447.                     }
  1448.                     $groupResults[$ruleName]['rules'][] = $ruleDetails;
  1449.                     $groupResults[$ruleName]['values'][] = $isMatched;
  1450.                 } else {
  1451.                     // Add standalone rule result
  1452.                     $data[$day][] = $ruleDetails;
  1453.                     $finalResult $this->evaluateCondition($finalResult$isMatched$ruleCondition);
  1454.                 }
  1455.             }
  1456.             $ruleIndex++;
  1457.         }
  1458.         // Process group results
  1459.         foreach ($groupResults as $groupName => $group) {
  1460.             $groupCondition = ($group['condition']) ? $group['condition'] : "AND";
  1461.             // Ensure $groupCondition is expanded to match the number of values
  1462.             $operators array_fill(0count($group['values']) - 1$groupCondition);
  1463.             // Evaluate conditions only if there are multiple values
  1464.             if (count($group['values']) > 1) {
  1465.                 $groupMatchResult \App\Lib\Utility::evaluateConditionsAdvanceCustomNotification($group['values'], $operators);
  1466.             } else {
  1467.                 // If there's only one value, use it directly
  1468.                 $groupMatchResult $group['values'][0];
  1469.             }
  1470.             $finalResult $this->evaluateCondition($finalResult$groupMatchResult$groupCondition);
  1471.             $data[] = [
  1472.                 'groupName' => $groupName,
  1473.                 'result' => $groupMatchResult,
  1474.                 'rules' => $group['rules'],
  1475.             ];
  1476.             if ($groupMatchResult) {
  1477.                 $matchedRules[] = $groupName;
  1478.             }
  1479.         }
  1480.         return [
  1481.             'finalResult' => $finalResult,
  1482.             'data' => $data,
  1483.         ];
  1484.     }
  1485.     private function evaluateSingleRule($rule$startDateObj$endDateObj$timezone): array
  1486.     {
  1487.         $duration $rule->getTimeInterval();
  1488.         $param $rule->getParameter()->getParamKey();
  1489.         $paramName $rule->getParameter()->getParamName("en");
  1490.         $unit $rule->getParameterUnitKey();
  1491.         $coordinates json_decode($rule->getLocation()->getCoordinates(), true);
  1492.         $heightDepth $rule->getHeightOrDepth();
  1493.         $resolution 'PT1H';
  1494.         $formattedCoordinates "";
  1495.         $model $rule->getModelParam() !== "model"
  1496.             "mix&calibrated=true"
  1497.             : ($rule->getModelValue() ?: 'mix');
  1498.         // Construct parameter string
  1499.         $parametersStr $param;
  1500.         if ($heightDepth) {
  1501.             $parametersStr .= '_' $heightDepth;
  1502.         }
  1503.         if ($duration) {
  1504.             $parametersStr .= '_' $duration 'h';
  1505.         }
  1506.         if ($unit) {
  1507.             $parametersStr .= ':' $unit;
  1508.         }
  1509.         // Format coordinates
  1510.         $formattedCoordinates count($coordinates) > 1
  1511.             implode('+'array_map(fn($coordinate) => implode(','$coordinate), $coordinates))
  1512.             : implode(','$coordinates[0]);
  1513.         // Construct the URL for Meteomatics API
  1514.         $startDate $startDateObj->format('Y-m-d\T00:00:00.v\Z');
  1515.         $endDate $endDateObj->format('Y-m-d\T23:59:59.v\Z');
  1516.         $url "{$this->apiBaseUrl}/{$startDate}--{$endDate}:{$resolution}/{$parametersStr}/{$formattedCoordinates}/json?source={$model}&use_decluttered=true";
  1517.         // Fetch data from Meteomatics
  1518.         $client = new Client(['verify' => false]);
  1519.         $response $client->request('GET'$url, [
  1520.             'auth' => [$this->username$this->password],
  1521.         ]);
  1522.         $data json_decode($response->getBody(), true);
  1523.         $qualifiedLocations $data['data'][0]['coordinates'][0]['dates'];
  1524.         $matched false;
  1525.         $ruleData = [];
  1526.         foreach ($qualifiedLocations as $location) {
  1527.             $value $location['value'];
  1528.             $date = new \DateTime($location['date'], new \DateTimeZone("UTC"));
  1529.             $date->setTimezone($timezone);
  1530.             $condition $rule->getCondition();
  1531.             $minValue $rule->getConditionValueMin();
  1532.             $maxValue $rule->getConditionValueMax();
  1533.             if ($condition == "range") {
  1534.                 $matched \App\Lib\Utility::compareValues($condition$value, [$minValue$maxValue]);
  1535.             } else {
  1536.                 $matched \App\Lib\Utility::compareValues($condition$value$minValue);
  1537.             }
  1538.             if ($matched) {
  1539.                 $ruleData[] = [
  1540.                     'date' => $date->format('Y-m-d H:i'),
  1541.                     'value' => $value,
  1542.                     'location' => $rule->getLocation()->getName(),
  1543.                 ];
  1544.             }
  1545.         }
  1546.         return [
  1547.             'rule_name' => $rule->getName(),
  1548.             'matched' => $matched,
  1549.             'data' => $ruleData,
  1550.         ];
  1551.     }
  1552.     private function evaluateCondition($currentResult$newResult$condition)
  1553.     {
  1554.         if ($condition === 'AND') {
  1555.             return $currentResult && $newResult;
  1556.         } elseif ($condition === 'OR') {
  1557.             return $currentResult || $newResult;
  1558.         }
  1559.         return $currentResult;
  1560.     }
  1561. }