"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BookingService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("typeorm");
const typeorm_2 = require("@nestjs/typeorm");
const userlocation_entity_1 = require("../../common/userlocation/userlocation.entity");
const booking_entity_1 = require("../../common/booking/booking.entity");
const bookingrequest_entity_1 = require("../../common/booking/bookingrequest.entity");
const userlocation_service_1 = require("../userlocation/userlocation.service");
const user_services_1 = require("../user/user.services");
const admin_driver_service_1 = require("../../adminapi/driver/admin.driver.service");
const driver_review_service_1 = require("../driverreview/driver-review.service");
const driver_entity_1 = require("../../common/driver/driver.entity");
const shop_entity_1 = require("../../common/shop/shop.entity");
let BookingService = class BookingService {
    constructor(userLocationRepository, bookingRepository, bookingRequestRepository, userLocationService, userService, adminDriverService, driverRepository, shopRepository, driverReviewService) {
        this.userLocationRepository = userLocationRepository;
        this.bookingRepository = bookingRepository;
        this.bookingRequestRepository = bookingRequestRepository;
        this.userLocationService = userLocationService;
        this.userService = userService;
        this.adminDriverService = adminDriverService;
        this.driverRepository = driverRepository;
        this.shopRepository = shopRepository;
        this.driverReviewService = driverReviewService;
    }
    async bookingRequest(createBookingRequestDto) {
        const nearbyDrivers = await this.userLocationService.getNearbyDrivers(createBookingRequestDto.pickupLatitude, createBookingRequestDto.pickupLongitude, createBookingRequestDto.radius, createBookingRequestDto.service);
        const requestId = createBookingRequestDto?.requestId;
        let existingDriverIds = [];
        if (requestId) {
            const existingRequests = await this.bookingRequestRepository.find({
                where: { requestId }
            });
            existingDriverIds = existingRequests.map(req => req.driverId);
        }
        const newDrivers = nearbyDrivers.filter(driver => !existingDriverIds.includes(driver.userId));
        const requests = newDrivers.map(driver => {
            const bookingRequest = this.bookingRequestRepository.create({
                requestId: createBookingRequestDto.requestId,
                userId: createBookingRequestDto.userId,
                driverId: driver.userId,
                carType: createBookingRequestDto.carType,
                color: createBookingRequestDto.color,
                model: createBookingRequestDto.model,
                year: createBookingRequestDto.year,
                description: createBookingRequestDto.description,
                pickupLatitude: createBookingRequestDto.pickupLatitude,
                pickupLongitude: createBookingRequestDto.pickupLongitude,
                dropLatitude: createBookingRequestDto.dropLatitude,
                dropLongitude: createBookingRequestDto.dropLongitude,
                pickupPlace: createBookingRequestDto.pickupPlace,
                dropPlace: createBookingRequestDto.dropPlace,
                service: createBookingRequestDto.service,
                scheduleType: createBookingRequestDto.scheduleType,
                scheduleDate: createBookingRequestDto.scheduleDate,
                scheduleTime: createBookingRequestDto.scheduleTime,
            });
            return this.bookingRequestRepository.save(bookingRequest);
        });
        return Promise.all(requests);
    }
    async confirmBooking(driverId, requestId) {
        const request = await this.bookingRequestRepository.findOne({
            where: { id: requestId, driverId },
        });
        if (!request || request.status !== 'pending') {
            throw new common_1.NotFoundException('Booking request not found or already handled');
        }
        request.status = 'accepted';
        await this.bookingRequestRepository.save(request);
        await this.bookingRequestRepository
            .createQueryBuilder()
            .update()
            .set({ status: 'expired' })
            .where('userId = :userId', { userId: request.userId })
            .andWhere('status = :status', { status: 'pending' })
            .andWhere('id != :id', { id: requestId })
            .execute();
        const booking = this.bookingRepository.create({
            userId: request.userId,
            driverId: request.driverId,
            carType: request.carType,
            color: request.color,
            model: request.model,
            year: request.year,
            pickupLatitude: request.pickupLatitude,
            pickupLongitude: request.pickupLongitude,
            dropLatitude: request.dropLatitude,
            dropLongitude: request.dropLongitude,
            pickupPlace: request.pickupPlace,
            dropPlace: request.dropPlace,
            service: request.service,
            status: 1,
            scheduleType: request.scheduleType,
            scheduleDate: request.scheduleDate,
            scheduleTime: request.scheduleTime,
        });
        const savedBooking = await this.bookingRepository.save(booking);
        const user = await this.userService.findById(request.userId);
        return {
            ...savedBooking,
            user: {
                name: user.name,
                email: user.email,
                mobile: user.mobileNumber
            },
        };
    }
    async updateBookingStatus(bookingId, status) {
        const booking = await this.bookingRepository.findOne({ where: { id: bookingId } });
        const booking2 = await this.bookingRequestRepository.findOne({ where: { id: bookingId } });
        if (!booking) {
            throw new common_1.NotFoundException(`Booking with ID ${bookingId} not found`);
        }
        booking.status = status;
        const updatedBooking = await this.bookingRepository.save(booking);
        return updatedBooking;
    }
    async getNearbyDrivers(latitude, longitude, radius) {
        const radiusInMeters = radius * 1000;
        return this.userLocationRepository
            .createQueryBuilder("user_location")
            .innerJoin("user", "user", "user.id = user_location.userId")
            .innerJoin("driver", "driver", "driver.userId = user.id")
            .where(`
      ST_Distance_Sphere(
        point(user_location.longitude, user_location.latitude),
        point(:lng, :lat)
      ) <= :radiusInMeters
    `, { lat: latitude, lng: longitude, radiusInMeters })
            .andWhere("driver.online = :online", { online: 1 })
            .select([
            "user_location.id",
            "user_location.latitude",
            "user_location.longitude",
            "driver.id",
            "driver.online"
        ])
            .getRawMany();
    }
    async getBookingRequests(driverId, status, scheduleType) {
        const whereClause = {
            driverId: driverId,
            status: status,
            scheduleType: scheduleType ? scheduleType : (0, typeorm_1.In)(['now', 'schedule']),
        };
        return this.bookingRequestRepository.find({
            where: whereClause,
            order: { id: 'DESC' },
        });
    }
    async getOnGoingBookingRequests(driverId, scheduleType) {
        const where = {
            driverId: driverId,
            status: (0, typeorm_1.In)([1, 2, 3]),
        };
        if (scheduleType) {
            where.scheduleType = scheduleType;
        }
        return await this.bookingRepository.find({
            where,
            order: { id: 'DESC' },
        });
    }
    async getBookingDetail(userId) {
        const bookings = await this.bookingRepository.find({
            where: [
                { userId: userId },
                { driverId: userId },
            ],
            order: { createdAt: "DESC" },
        });
        if (!bookings.length) {
            return null;
        }
        const booking = bookings[0];
        const userInfo = await this.userService.findById(booking.userId);
        const driverInfo = await this.adminDriverService.findDriverDetail(booking.driverId);
        const driverAvgRating = await this.driverReviewService.getDriverAverage(booking.driverId.toString());
        let shopInfo = null;
        try {
            const driverRecord = await this.driverRepository.findOne({
                where: { user: { id: userId } },
                relations: ['user'],
            });
            if (driverRecord && driverRecord.shopId) {
                const shop = await this.shopRepository.findOne({
                    where: { id: driverRecord.shopId },
                });
                if (shop) {
                    shopInfo = {
                        shopId: shop.id,
                        shopName: shop.name,
                    };
                }
            }
        }
        catch (error) {
            console.error('Error fetching shop info:', error);
        }
        return {
            bookingId: booking.id,
            status: booking.status,
            statusText: this.mapStatus(booking.status),
            pickupPlace: booking.pickupPlace,
            dropPlace: booking.dropPlace,
            createdAt: booking.createdAt,
            scheduleType: booking.scheduleType,
            scheduleDate: booking.scheduleDate,
            scheduleTime: booking.scheduleTime,
            booking: booking,
            user: userInfo,
            driver: {
                ...driverInfo,
                averageRating: driverAvgRating,
            },
            shop: shopInfo,
        };
    }
    mapStatus(status) {
        switch (status) {
            case 0: return 'Pending';
            case 1: return 'Accept';
            case 2: return 'At pickup';
            case 3: return 'Start trip';
            case 4: return 'End trip';
            case 5: return 'Expired';
            default: return 'Unknown';
        }
    }
};
exports.BookingService = BookingService;
exports.BookingService = BookingService = __decorate([
    (0, common_1.Injectable)(),
    __param(0, (0, typeorm_2.InjectRepository)(userlocation_entity_1.UserLocation)),
    __param(1, (0, typeorm_2.InjectRepository)(booking_entity_1.Booking)),
    __param(2, (0, typeorm_2.InjectRepository)(bookingrequest_entity_1.BookingRequest)),
    __param(6, (0, typeorm_2.InjectRepository)(driver_entity_1.Driver)),
    __param(7, (0, typeorm_2.InjectRepository)(shop_entity_1.Shop)),
    __param(8, (0, common_1.Inject)((0, common_1.forwardRef)(() => driver_review_service_1.DriverReviewService))),
    __metadata("design:paramtypes", [typeorm_1.Repository,
        typeorm_1.Repository,
        typeorm_1.Repository,
        userlocation_service_1.UserLocationService,
        user_services_1.UserService,
        admin_driver_service_1.AdminDriverService,
        typeorm_1.Repository,
        typeorm_1.Repository,
        driver_review_service_1.DriverReviewService])
], BookingService);
//# sourceMappingURL=booking.service.js.map