<?php



namespace Modules\Trip\Controllers\Api;







use App\Controllers\BaseController;

use Modules\Trip\Models\TripModel;

use Modules\Trip\Models\StuffassignModel;

use Modules\Trip\Models\SubtripModel;

use Modules\Trip\Models\PickdropModel;

use Modules\Location\Models\LocationModel;

use Modules\Employee\Models\EmployeeModel;

use Modules\Fleet\Models\FleetModel;

use Modules\Fleet\Models\VehicleModel;

use Modules\Schedule\Models\ScheduleModel;

use CodeIgniter\API\ResponseTrait;

use CodeIgniter\Database\RawSql;

use Modules\Rating\Models\RatingModel;

use Modules\Cancellation\Models\GlobalCancellationModel;

use Modules\Trip\Models\RoundtripdiscoundModel;



use Modules\Ticket\Models\TicketModel;

use App\Libraries\BookingInventorySupport;

use App\Libraries\OvernightTripRunSupport;
use App\Libraries\TripListSeatCountEstimator;

use Modules\Offer\Models\OfferModel;

use Modules\Page\Models\PrivacyModel;
use Modules\Page\Models\TermsModel;




class Trip extends BaseController

{

    use ResponseTrait;



    protected $Viewpath;

    protected $tripModel;

    protected $subtripModel;

    protected $stuffassignModel;

    protected $locationModel;

    protected $employeeModel;

    protected $fleetTypeModel;

    protected $scheduleeModel;

    protected $vehicleModel;

    protected $pickdropModel;

    protected $db;

    protected $ratingModel;

    protected $ticketModel;

    protected $globalCancellationModel;

    protected $picdropModel;
    
    protected $roundtripdiscoundModel;

    protected $offerModel;

    protected $privacyModel;

    protected $termsModel;



    public function __construct()

    {

        $this->Viewpath = "Modules\Trip\Views";

        $this->tripModel = new TripModel();

        $this->subtripModel = new SubtripModel();

        $this->stuffassignModel = new StuffassignModel();

        $this->locationModel = new LocationModel();

        $this->employeeModel = new EmployeeModel();

        $this->fleetTypeModel = new FleetModel();

        $this->vehicleModel = new VehicleModel();

        $this->scheduleeModel = new ScheduleModel();

        $this->pickdropModel = new PickdropModel();

        $this->picdropModel = new PickdropModel();

        $this->db = \Config\Database::connect();



        $this->ratingModel = new RatingModel();

        $this->ticketModel = new TicketModel();

        $this->offerModel = new OfferModel();

        $this->privacyModel = new PrivacyModel();

        $this->globalCancellationModel = new GlobalCancellationModel();

        $this->termsModel = new TermsModel();
        
        $this->roundtripdiscoundModel = new RoundtripdiscoundModel();

    }



    public function test()

    {

        echo "helo";

    }



    public function getAllTrip()

    {

        $fleet_id         = $this->request->getVar('fleet_id');

        $pick_location_id = $this->request->getVar('pick_location_id');

        $drop_location_id = $this->request->getVar('drop_location_id');

        $journey_date     = $this->request->getVar('journeydate');

        $offer = $this->request->getVar('offer')??"";

        $discountAmount = 0;
        $discountPercent = 0;
        $offerSeatClasses = [];


        if($offer != ""){
            $offers = $this->offerModel->where('code', $offer)
                                        // ->where('start_date <=', date('Y-m-d'))
                                        // ->where('end_date >=', date('Y-m-d'))
                                        ->first();
            if(isset($offers) && !empty($offers)){
                 $offerSeatClasses = !empty($offers->seat_class) ? json_decode($offers->seat_class, true) : [];
            
                if (is_array($offerSeatClasses)) {
                    $offerSeatClasses = array_map('strval', $offerSeatClasses);
                } else {
                    $offerSeatClasses = [];
                }
                if ($offers->discount_type == 1) {
                    $discountAmount = (float) $offers->discount;
                } elseif ($offers->discount_type == 2) {
                    $discountPercent = (float) $offers->discount;
                }
            }

        }

        




        $journeyDate = BookingInventorySupport::normalizeCalendarDate($journey_date);

        $journeyDayOfWeek = date('N', strtotime($journeyDate));

        $maxBookDay = get_egypt_time('+1 month')->format('Y-m-d');



        if (empty($pick_location_id)) {

            $data = [

                'message' => "Please pick a location",

                'status' => "failed",

                'response' => 204,

            ];

            return $this->response->setJSON($data);

        }



        if (empty($drop_location_id)) {

            $data = [

                'message' => "Please pick a droping point",

                'status' => "failed",

                'response' => 204,

            ];

            return $this->response->setJSON($data);

        }



        if (empty($journey_date)) {

            $data = [

                'message' => "Please select your journey date",

                'status' => "failed",

                'response' => 204,

            ];

            return $this->response->setJSON($data);

        }



        if (strtotime(egypt_today()) > strtotime($journeyDate)) {

            $data = [

                'message' => "No Past Data allow",

                'status' => "failed",

                'response' => 204,

            ];



            return $this->response->setJSON($data);

        }



        if (strtotime($journeyDate) > strtotime($maxBookDay)) {

            $data = [

                'message' => "No advance booking for this day",

                'status' => "failed",

                'response' => 204,

            ];

            return $this->response->setJSON($data);

        }



        // bind search query

        $main_privacy_policy = $this->termsModel->first();

        $this->subtripModel

            ->select('trips.id as tripid, trips.*, fleets.*, schedules.*, vehicles.*, subtrips.id as subtripId, subtrips.*, companies.name as companyName,companies.id as companyId, companies.logo as company_logo, company_terms.description as privacy_policy, trip_category.name as trip_category, trip_bus_types.name as trip_bus_types, GROUP_CONCAT(fleetimages.img_path) as bus_images')



            ->join('trips', 'trips.id = subtrips.trip_id')

            ->join('fleets', 'fleets.id = trips.fleet_id',"left")

            ->join('fleetimages', 'fleets.id = fleetimages.fleet_id',"left")

            ->join('schedules', 'schedules.id = trips.schedule_id',"left")

            ->join('vehicles', 'vehicles.id = trips.vehicle_id',"left")

            ->join('companies', 'trips.company_id = companies.id', 'left')

            ->join('company_terms', 'company_terms.company_id = companies.id', 'left')

            ->join('trip_category', 'trip_category.id = trips.trip_category_id', 'left')

            ->join('trip_bus_types', 'trip_bus_types.id = trips.trip_bus_type_id', 'left')

            ->join('vehicalimages', 'vehicalimages.vehicle_id = vehicles.id',"left")



            ->groupStart()

                ->groupStart()

                    ->where('subtrips.pick_location_id', $pick_location_id)

                    ->where('subtrips.drop_location_id', $drop_location_id)

                ->groupEnd()



                ->orGroupStart()

                    ->whereIn('subtrips.trip_id', function ($subQuery) use ($pick_location_id, $drop_location_id) {

                        $subQuery

                            ->select('sm.trip_id')

                            ->from('subtrips sm')

                            ->where('sm.pick_location_id', $pick_location_id)

                            ->where('sm.drop_location_id', $drop_location_id)

                            ->where('sm.type', 'subtrip');

                    })

                    ->where('subtrips.type', 'main')

                ->groupEnd()

            ->groupEnd()



            ->where('subtrips.status', 1)

            ->where('trips.status', 1)

            ->groupBy('subtrips.id')

            ->orderBy('subtrips.id', 'DESC');



        $this->db->transStart();

        $classDataRaw = $this->db->table('seat_class')

        ->get()

        ->getResult();

        $this->db->transComplete();

        $classData = [];

        foreach ($classDataRaw as $class) {

            $classData[$class->id] = $class;

        }
        $economy = new \stdClass();
        $economy->id = 999;
        $economy->name = "Economy class";
        
        $classData[999] = $economy;


        $fleet_id && $this->subtripModel->where('trips.fleet_id', $fleet_id);

        $allSubTrips =  $this->subtripModel->findAll();

        $data = array('trips' => [], 'in_holiday' => [], 'to_open' => [], 'inactive' => [], 'you_may_like' => []);

        $globalCancellationRows = $this->globalCancellationModel
            ->select('hours, charges')
            ->findAll();
        $globalCancelationPolicy = array_map(static function ($row) {
            return [
                'charges' => $row->charges,
                'hours'   => $row->hours,
            ];
        }, $globalCancellationRows);

        $overnightRun = new OvernightTripRunSupport();

        foreach ($allSubTrips as $subTrip) {

            $mainTripIdInt = (int) $subTrip->trip_id;
            $subtripIdInt  = (int) $subTrip->subtripId;

            $requiresPickstand = $overnightRun->clientMustSelectPickstand($mainTripIdInt, $subtripIdInt);
            $eligiblePickStands = $overnightRun->pickStandsForBoardingSearchDate($mainTripIdInt, $subtripIdInt, $journeyDate);
            if ($eligiblePickStands === []) {
                continue;
            }

            // App / website boarding dropdown: all segment pickups on overnight runs (admin parity).
            $pickupPickerStandIds = $overnightRun->pickStandsForPickupPicker($mainTripIdInt, $subtripIdInt, $journeyDate);

            $pickStandId = (int) ($this->request->getVar('pickstand') ?? $this->request->getVar('pickstand_id') ?? 0);
            $awaitingPickstand = $requiresPickstand && $pickStandId <= 0;

            if (! $awaitingPickstand && $pickStandId <= 0) {
                $pickStandId = $eligiblePickStands[0];
            }

            // Schedule/bus-run dates use a representative pickup; seat counts wait for explicit pickstand.
            $pickStandForSchedule = $pickStandId > 0 ? $pickStandId : ($eligiblePickStands[0] ?? 0);

            $departureDates = BookingInventorySupport::resolveSearchDepartureDates(
                $mainTripIdInt,
                $subtripIdInt,
                $journeyDate,
                $pickStandForSchedule
            );
            $busStartDate = $departureDates['bus_start'];
            $busStartDayOfWeek = date('N', strtotime($busStartDate));

            // build rating for trip

            $totalRating = $this->ratingModel

                ->select('COUNT(*) AS t_rat, SUM(rating) AS s_rat, AVG(rating) AS avg_rat')

                ->where('subtrip_id', $subTrip->subtripId)

                ->where('status', 1)

                ->first();

            // $stoppages = $this->locationModel

            //                     ->select('id, name')

            //                     ->whereIn('id', array_filter(explode(',', $subTrip->stoppage)))
            //                     ->whereNotIn('id', [$drop_location_id, $pick_location_id])
            //                     ->findAll();
                                
            $stoppages = $this->locationModel
                            ->select('id, name')
                            ->whereIn('id', array_filter(explode(',', $subTrip->stoppage)))
                            ->whereNotIn('id', [$drop_location_id, $pick_location_id])
                            ->findAll();


            $subTrip->stoppage_stand = array_column($stoppages, 'name', 'id');
            
             $roundtripDiscount = $this->roundtripdiscoundModel
                ->where('status', 1)
                ->where('company_id', $subTrip->companyId)
                ->first();
            
            // Add roundTripDiscount key to trip data
            $subTrip->roundTripDiscount = !empty($roundtripDiscount) ? (float) $roundtripDiscount->onlinediscountrate : 0;

            $subtripSeatclass = json_decode($subTrip->subtrip_seatclass, true);

            $subtripSeatclass[] = [
                "seatClass" => "999",
                "seatNo" => [],
                "fare" => $subTrip->adult_fair
            ];
            
            // Encode back if needed
            $subTrip->subtrip_seatclass = json_encode($subtripSeatclass);

            $subtripSeatClassArray = json_decode($subTrip->subtrip_seatclass, true);

            $seatClassDetails = [];



            if (!empty($subTrip->subtrip_seatclass) && is_string($subTrip->subtrip_seatclass)) {

                $subtripSeatClassArray = json_decode($subTrip->subtrip_seatclass, true);


                if (json_last_error() === JSON_ERROR_NONE && is_array($subtripSeatClassArray)) {

                    foreach ($subtripSeatClassArray as $item) {
                        
                        $currentSeatClassId = isset($item['seatClass']) ? (string) $item['seatClass'] : '';
                        
                        $shouldApplyDiscount = false;
                        if($offer != ""){
                            
                            if (empty($offerSeatClasses) || in_array($currentSeatClassId, $offerSeatClasses)) {
                                $shouldApplyDiscount = true;
                            }
                        }
                        
                        if($offer != "" && $shouldApplyDiscount){

                            if($discountAmount !=  0){
                                    $seatClassDetails[] = [

                                    'seatClass' => $item['seatClass'] ?$classData[$item['seatClass']]->name :'',

                                    'seatClassId' => $item['seatClass'] ?? '',

                                    'fare'      => $item['fare'] ?? '',

                                    'discountAmount' => $discountAmount,

                                    'FinalFare' => $discountAmount ? max(0, $item['fare'] - $discountAmount) : $item['fare'],


                                ];

                            }else if ($discountPercent != 0) {

                                // $discountAmount = ($item['fare'] ?? 0) * ($discountPercent / 100);

                                // // Calculate final fare ensuring it doesn't go below 0
                                // $finalFare = max(0, ($item['fare'] ?? 0) - $discountAmount);

                                $seatClassDetails[] = [
                                    'seatClass'      => $item['seatClass'] ? $classData[$item['seatClass']]->name : '',
                                    'seatClassId'    => $item['seatClass'] ?? '',
                                    'fare'           => $item['fare'] ?? 0,
                                    'discountAmount' => round($item['fare'] && $discountPercent ? ($item['fare'] * $discountPercent) / 100 : 0, 2),
                                    'FinalFare'      => round(max(0, ($item['fare'] ?? 0) - ($item['fare'] && $discountPercent ? ($item['fare'] * $discountPercent) / 100 : 0)), 2),

                                ];
                            }else{
                                $seatClassDetails[] = [

                                'seatClass' => $item['seatClass'] ?$classData[$item['seatClass']]->name :'',

                                'seatClassId' => $item['seatClass'] ?? '',

                                'fare'      => $item['fare'] ?? '',

                                'discountAmount' => 0,

                                'FinalFare'      => $item['fare'] ?? '',

                                ];

                            }
                            

                        }else{

                            $seatClassDetails[] = [

                                'seatClass' => $item['seatClass'] ?$classData[$item['seatClass']]->name :'',

                                'seatClassId' => $item['seatClass'] ?? '',

                                'fare'      => $item['fare'] ?? '',

                                'discountAmount' => 0,

                                'FinalFare'      => $item['fare'] ?? '',

                            ];

                        }

                    }

                }

            }





            $subTrip->seatclass_price = $seatClassDetails;



            

            $facilityIds = array_filter(explode(',', $subTrip->facility ?? ''));



            $facilitys = [];



            if (!empty($facilityIds)) {

                $this->db->transStart();

                $facilitys = $this->db->table('facilitys')

                    ->whereIn('id', $facilityIds)

                    ->get()

                    ->getResult();

                $this->db->transComplete();

            }



            

            $subTrip->facility = implode(",", array_column($facilitys, 'name', 'id'));



            $subTrip->cancelation_policy = $globalCancelationPolicy;





            $totalRating = $this->ratingModel

                ->select('COUNT(*) AS t_rat, SUM(rating) AS s_rat, AVG(rating) AS avg_rat')

                ->where('subtrip_id', $subTrip->subtripId)

                ->where('status', 1)

                ->first();



            $subTrip->rating = number_format($totalRating->avg_rat, 1);







            $pickup_time = null;

            $drop_time = null;

            $pickup_list = [];

            $drop_list   = [];



            $pickdropSelect = 'pickdrops.id as pickdropid, pickdrops.trip_id, pickdrops.stand_id, pickdrops.time, '
                . 'pickdrops.type as pickdrop_type, pickdrops.detail, stands.name as stand_name';

            $pickdrop = $this->pickdropModel->select($pickdropSelect)
                ->join('stands', 'stands.id = pickdrops.stand_id')
                ->where('trip_id', $subTrip->id)
                ->orderBy('pickdrops.id', 'ASC')
                ->findAll();

            if (empty($pickdrop)) {
                $pickdrop = $this->pickdropModel->select($pickdropSelect)
                    ->join('stands', 'stands.id = pickdrops.stand_id')
                    ->where('trip_id', $subTrip->trip_id)
                    ->orderBy('pickdrops.id', 'ASC')
                    ->findAll();
            }

            // print_r($pickdrop);

            $subTripStartTime = $subTrip->start_time; // e.g. "09:00:00"
            $last_stop_time = $subTripStartTime;
            $current_day_offset = 0;
            $searched_pickup_offset = 0;
            $max_drop_offset = 0;
            $earliest_pickup_time = null;
            $latest_drop_time = null;
            
            $pickup_time = null;
            $drop_time = null;
            $pickup_list = [];
            $drop_list   = [];

            // Trace day offsets through all stops in chronological order
            foreach ($pickdrop as $item) {
                $item_time = $item->time;
                
                // Detect day rollover (heuristic: if current time < last stop time, a day has passed)
                // Note: This assumes stops are entered in chronological order.
                if (strtotime("1970-01-01 " . $item_time) < strtotime("1970-01-01 " . $last_stop_time)) {
                    $current_day_offset++;
                }
                $last_stop_time = $item_time;

                $pickdropType = (int) ($item->pickdrop_type ?? $item->type ?? 0);
                $pickdropId   = (int) ($item->pickdropid ?? 0);
                $placeLabel   = trim((string) ($item->detail ?? ''));
                if ($placeLabel === '') {
                    $placeLabel = trim((string) ($item->stand_name ?? $item->name ?? ''));
                }

                if ($pickdropType === 1) { // Pickup
                    // Smallest pickup time
                    if (is_null($pickup_time) || strtotime($item->time) < strtotime($pickup_time)) {
                        $pickup_time = $item->time;
                    }
                    
                    $pickup_list[] = [
                        'id' => $pickdropId,
                        'time' => $item->time,
                        'place' => $placeLabel,
                        'pickid' => $pickdropId,
                        'offset' => $current_day_offset // Store offset for debugging/display if needed
                    ];
                    
                    // The start time of this sub-trip (from the user's perspective) 
                    // is the time of the first pickup point.
                    if (is_null($earliest_pickup_time)) {
                        $searched_pickup_offset = $current_day_offset;
                        $earliest_pickup_time = $item_time;
                    } else if (($current_day_offset * 86400 + strtotime("1970-01-01 " . $item_time)) < ($searched_pickup_offset * 86400 + strtotime("1970-01-01 " . $earliest_pickup_time))) {
                        $searched_pickup_offset = $current_day_offset;
                        $earliest_pickup_time = $item_time;
                    }
                } elseif ($pickdropType === 0) { // Drop
                    // Largest drop time
                    if (is_null($drop_time) || strtotime($item->time) > strtotime($drop_time)) {
                        $drop_time = $item->time;
                    }
                    
                    $drop_list[] = [
                        'id' => $pickdropId,
                        'time' => $item->time,
                        'place' => $placeLabel,
                        'dropid' => $pickdropId,
                        'offset' => $current_day_offset
                    ];
                    
                    if ($item->stand_id == $drop_location_id) {
                        $latest_drop_time = $item_time;
                        $max_drop_offset = $current_day_offset;
                    }
                }
            }

            // Fallback for offsets if location-specific check didn't trigger
            if (is_null($earliest_pickup_time)) {
                // If we didn't find the specific stand (unlikely in sub-trip), use 1st pickup
                foreach ($pickdrop as $p) {
                    if ((int) ($p->pickdrop_type ?? $p->type ?? 0) === 1) {
                        $earliest_pickup_time = $p->time;
                        break;
                    }
                }
            }
            if (is_null($latest_drop_time)) {
                foreach (array_reverse($pickdrop) as $p) {
                    if ((int) ($p->pickdrop_type ?? $p->type ?? 0) === 0) {
                        $latest_drop_time = $p->time;
                        break;
                    }
                }
            }

            // Overnight: show every segment pickup in the picker (admin parity). Same-day: boarding-day filter.
            $pickerStandFlip = array_flip($pickupPickerStandIds);
            if ($requiresPickstand) {
                $pickup_list = array_values(array_filter($pickup_list, static function ($row) use ($pickerStandFlip) {
                    $pickdropId = (int) ($row['pickid'] ?? $row['id'] ?? 0);

                    return $pickdropId > 0 && isset($pickerStandFlip[$pickdropId]);
                }));
            } else {
                $eligiblePickFlip = array_flip($eligiblePickStands);
                $pickup_list = array_values(array_filter($pickup_list, static function ($row) use ($eligiblePickFlip) {
                    $pickdropId = (int) ($row['pickid'] ?? $row['id'] ?? 0);

                    return $pickdropId > 0 && isset($eligiblePickFlip[$pickdropId]);
                }));
            }

            if ($requiresPickstand && $pickup_list !== []) {
                $boardingHelper = new \App\Libraries\TripJourneyDateHelper();
                $hasEveningOnSearch = $boardingHelper->segmentHasEveningPickupOnSearchDate(
                    $mainTripIdInt,
                    $subtripIdInt,
                    $journeyDate
                );
                foreach ($pickup_list as $idx => $row) {
                    $pickdropId = (int) ($row['pickid'] ?? $row['id'] ?? 0);
                    $pickOffset = (int) ($row['offset'] ?? 0);
                    $runForPickup = $boardingHelper->boardingDayToBusRunDate(
                        $mainTripIdInt,
                        $subtripIdInt,
                        $journeyDate,
                        $pickdropId
                    );
                    $boardingFromPriorRun = $boardingHelper->getBoardingDateFromBusStartDate(
                        $mainTripIdInt,
                        $subtripIdInt,
                        $runForPickup,
                        $pickdropId
                    );
                    $boardingFromServiceBus = $boardingHelper->getBoardingDateFromBusStartDate(
                        $mainTripIdInt,
                        $subtripIdInt,
                        $busStartDate,
                        $pickdropId
                    );
                    if ($pickOffset >= 1
                        && $hasEveningOnSearch
                        && $busStartDate === $journeyDate
                        && $boardingFromServiceBus > $journeyDate
                    ) {
                        $pickup_list[$idx]['boarding_date'] = $boardingFromServiceBus;
                    } else {
                        $pickup_list[$idx]['boarding_date'] = $boardingFromPriorRun;
                    }
                }
            }

            // Display-only seat count: same inventory path as seatnew when pickstand is sent.
            $pickStandForInventory = $pickStandId > 0 ? $pickStandId : $pickStandForSchedule;
            $seatCountEstimate = (new TripListSeatCountEstimator($this->db))->estimateForSubtrip(
                $mainTripIdInt,
                $subtripIdInt,
                $journeyDate,
                (int) $subTrip->pick_location_id,
                (int) $subTrip->drop_location_id,
                (int) $subTrip->total_seat,
                $pickStandForInventory,
                $awaitingPickstand
            );
            $subTrip->booked_seats = $seatCountEstimate['booked_seats'];
            $subTrip->totalbooking = $seatCountEstimate['totalbooking'];
            $subTrip->available_seat = $seatCountEstimate['available_seat'];
            $subTrip->seat_count_estimated = $seatCountEstimate['seat_count_estimated'];



            // The absolute drop time for this bus instance
            $dropDate = date('Y-m-d', strtotime($busStartDate . " +$max_drop_offset day"));
            $journeyDateTime = new \DateTime("$dropDate $latest_drop_time");

            // Boarding DateTime for the passenger at the searched location


            $egyptNow = get_egypt_time();
            $nowPlusTwoHours = (clone $egyptNow)->modify('+2 hours');
            $runContext = $overnightRun->resolveBoardingSearch($mainTripIdInt, $subtripIdInt, $journeyDate, $pickStandForSchedule);
            $boardingDateTime = new \DateTime($runContext['boarding_datetime'], new \DateTimeZone('Africa/Cairo'));

            // Hide trip if it starts within 2 hours from now
            if ($nowPlusTwoHours > $boardingDateTime) {
                $data['in_holiday'][] = $subTrip;
                continue;
            }





            if ($subTrip->status == 0) {

                // subtrip is inactive

                $data['inactive'][] = $subTrip;

                continue;

            }

            // The true departure time for this passenger's sub-trip
            // (Already checked above with $boardingDateTime)



            if (strtotime($busStartDate) < strtotime($subTrip->startdate)) {

                // subtrip yet not begin

                $data['to_open'][] = $subTrip;

                continue;

            }



            $cleanedoffdates = preg_replace('/\s+/', '', $subTrip->offdates);

            if (in_array($busStartDate, explode(',', $cleanedoffdates))) {

                // subtrip is off today

                $data['in_holiday'][] = $subTrip;

                continue;

            }

            if ($this->isDateInRange($busStartDate, $subTrip->startdateinrange, $subTrip->enddateinrange)) {

                // subtrip is not in range

                $data['in_holiday'][] = $subTrip;

                continue;

            }

            $offdateranges = json_decode($subTrip->offdateranges, true);

            $isInAnyRange = false;

            if (is_array($offdateranges) && !empty($offdateranges)) {

                foreach ($offdateranges as $range) {

                    $start = $range['start'] ?? null;

                    $end = $range['end'] ?? null;



                    if ($start && $end && $this->isDateInRange($busStartDate, $start, $end)) {

                        $isInAnyRange = true;

                        break;

                    }

                }

            }



            if ($isInAnyRange) {

                $data['in_holiday'][] = $subTrip;

                continue;

            }

            // Existence and repetition checks use the adjusted $busStartDate
            if (!$this->isDateInRange($busStartDate, $subTrip->repetedstartdate, $subTrip->repetedenddate)) {

                if($busStartDate != date('Y-m-d',strtotime($subTrip->startdate))){

                    //start date and not between start and edn date

                    $data['in_holiday'][] = $subTrip;

                    continue;    

                }

                

            }



            if (@in_array($busStartDayOfWeek, explode(',', $subTrip->weekend))) {
                $data['in_holiday'][] = $subTrip;
                continue;
            }



            // The 'journeydate' returned to the API should be the date the passenger actually boards!
            $subTrip->journeydate = $journeyDate; 
            // We provide the physical bus start date as well for the booking process
            $subTrip->busStartDate = $busStartDate;
            $subTrip->requires_pickstand = $requiresPickstand;
            $subTrip->eligiblePickStandIds = $pickupPickerStandIds;
            $subTrip->pickup_points = $pickup_list;
            $subTrip->drop_points   = $drop_list;

            if (($subTrip->pick_location_id != $pick_location_id) || ($subTrip->drop_location_id != $drop_location_id)) {

                // subtrip is related to selected locations

                $data['you_may_like'][] = $subTrip;

                continue;

            }

            $subTrip->privacy_policy = !empty($subTrip->privacy_policy) ? strip_tags($subTrip->privacy_policy) : "";



            $subTrip->company_logo = !empty($subTrip->company_logo) ? "https://data.busvalley.net/busvalley_new/public/".$subTrip->company_logo : "";

            $subTrip->privacy_policy = !empty($subTrip->privacy_policy) ? strip_tags($subTrip->privacy_policy) : "";

            if (!empty($subTrip->bus_images)) {

                $pics = explode(',', $subTrip->bus_images);

                $subTrip->bus_images = array_map(function($pic) {

                    return "https://data.busvalley.net/busvalley_new/public/" . trim($pic);

                }, $pics);

            } else {

                $subTrip->bus_images = [];

            }
            
            $subTrip->main_privacy_policy = $main_privacy_policy ?? "";
            $data['trips'][] = $subTrip;

        }



        if (!count($data['trips']) && !count($data['you_may_like'])) {

            if (count($data['in_holiday'])) {

                return $this->response->setJSON([

                    'message' => "Holiday for all trips! No trip found.",

                    'status' => "failed",

                    'response' => 204,

                ]);

            }



            if (count($data['to_open'])) {

                return $this->response->setJSON([

                    'message' => "Trips yet not started! No trip found.",

                    'status' => "failed",

                    'response' => 204,

                ]);

            }



            return $this->response->setJSON([

                'message' => "No trip found for this route!",

                'status' => "failed",

                'response' => 204,

            ]);

        }


        return $this->response->setJSON([

            'status' => "success",

            'response' => 200,

            'data' => $data['trips'],

            'suggestions' => $data['you_may_like']

        ]);

    }



    public function showsubtrip()

    {

        $url = base_url();

        $allFronSubTrip =  $this->subtripModel->select('trips.id as tripid,trips.*,schedules.*,subtrips.id as subtripId,subtrips.*')

            ->join('trips', 'trips.id = subtrips.trip_id')

            ->join('schedules', 'schedules.id = trips.schedule_id')

            ->where('subtrips.status', 1)

            ->where('subtrips.show', 1)

            ->findAll();



        if ($allFronSubTrip) {

            foreach ($allFronSubTrip as $key => $value) {

                $value->imglocation = $url . '/public/' . $value->imglocation;

            }



            $data = [

                'status' => "success",

                'response' => 200,

                'data' => $allFronSubTrip,

            ];



            return $this->response->setJSON($data);

        } else {

            $data = [

                'message' => "No trip found for this location",

                'status' => "failed",

                'response' => 204,

            ];



            return $this->response->setJSON($data);

        }

    }



    public function boarding($id)

    {

        $boarding =  $this->pickdropModel->where('type', 1)->where('trip_id', $id)->findAll();



        if ($boarding) {



            $data = [

                'status' => "success",

                'response' => 200,

                'data' => $boarding,

            ];



            return $this->response->setJSON($data);

        } else {

            $data = [

                'message' => "No Boarding Pint Found",

                'status' => "failed",

                'response' => 204,

            ];



            return $this->response->setJSON($data);

        }

    }



    public function dropping($id)

    {

        $boarding =  $this->pickdropModel->where('type', 0)->where('trip_id', $id)->findAll();



        if ($boarding) {



            $data = [

                'status' => "success",

                'response' => 200,

                'data' => $boarding,

            ];



            return $this->response->setJSON($data);

        } else {

            $data = [

                'message' => "No Dropping Pint Found",

                'status' => "failed",

                'response' => 204,

            ];



            return $this->response->setJSON($data);

        }

    }

    public function getClassName($id){

        $this->db->transStart();

        $classData = $this->db->table('seat_class')

        ->get()

        ->getResult();

        $this->db->transComplete();



        $data = [

            'status' => "success",

            'response' => 200,

            'data' => $classData,

        ];

        return $this->response->setJSON($data);

    }

    public function isDateInRange($dateToCheck, $startDate, $endDate) {

        // Convert dates to DateTime objects

        $date       = new \DateTime($dateToCheck);

        $start      = new \DateTime($startDate);

        $end        = new \DateTime($endDate);



        // Check if the date is in the range

        return ($date >= $start && $date <= $end);

    }

}

