<?php
/**
 * Complete Bookings Controller
 * Full CRUD operations with database integration
 */

class BookingsController {
    private $db;
    private $config;

    public function __construct($db, $config) {
        $this->db = $db;
        $this->config = $config;
    }

    /**
     * GET /api/bookings
     * Get all bookings with filters
     */
    public function getAll($filters = []) {
        try {
            $query = "
                SELECT 
                    b.id, b.booking_reference, b.guest_id, b.property_id, b.room_id,
                    b.check_in, b.check_out, b.status, b.price, b.nights,
                    b.source, b.guest_token, b.notes, b.created_at, b.updated_at,
                    g.name as guest_name, g.email as guest_email, g.phone as guest_phone,
                    p.name as property_name, r.name as room_name
                FROM bookings b
                JOIN guests g ON b.guest_id = g.id
                JOIN properties p ON b.property_id = p.id
                LEFT JOIN rooms r ON b.room_id = r.id
                WHERE 1=1
            ";

            $params = [];

            // Filter by property
            if (!empty($filters['property_id'])) {
                $query .= " AND b.property_id = ?";
                $params[] = $filters['property_id'];
            }

            // Filter by status
            if (!empty($filters['status'])) {
                $query .= " AND b.status = ?";
                $params[] = $filters['status'];
            }

            // Filter by date range
            if (!empty($filters['check_in_from'])) {
                $query .= " AND b.check_in >= ?";
                $params[] = $filters['check_in_from'];
            }
            if (!empty($filters['check_in_to'])) {
                $query .= " AND b.check_in <= ?";
                $params[] = $filters['check_in_to'];
            }

            $query .= " ORDER BY b.check_in DESC";

            $stmt = $this->db->prepare($query);
            $stmt->execute($params);
            $bookings = $stmt->fetchAll(PDO::FETCH_ASSOC);

            return [
                'success' => true,
                'count' => count($bookings),
                'bookings' => $bookings
            ];

        } catch (Exception $e) {
            error_log('Error fetching bookings: ' . $e->getMessage());
            return ['success' => false, 'message' => 'Error fetching bookings'];
        }
    }

    /**
     * GET /api/bookings/{id}
     * Get single booking
     */
    public function getById($id) {
        try {
            $stmt = $this->db->prepare("
                SELECT 
                    b.*, 
                    g.name as guest_name, g.email as guest_email, g.phone as guest_phone, g.address,
                    p.name as property_name,
                    r.name as room_name, r.type as room_type
                FROM bookings b
                JOIN guests g ON b.guest_id = g.id
                JOIN properties p ON b.property_id = p.id
                LEFT JOIN rooms r ON b.room_id = r.id
                WHERE b.id = ?
            ");
            $stmt->execute([$id]);
            $booking = $stmt->fetch(PDO::FETCH_ASSOC);

            if (!$booking) {
                return ['success' => false, 'message' => 'Booking not found'];
            }

            return ['success' => true, 'booking' => $booking];

        } catch (Exception $e) {
            return ['success' => false, 'message' => 'Error fetching booking'];
        }
    }

    /**
     * POST /api/bookings
     * Create new booking
     */
    public function create($data) {
        // Validate required fields
        $required = ['guest_id', 'property_id', 'check_in', 'check_out', 'price'];
        foreach ($required as $field) {
            if (empty($data[$field])) {
                return ['success' => false, 'message' => ucfirst($field) . ' is required'];
            }
        }

        try {
            // Calculate nights
            $checkin = new DateTime($data['check_in']);
            $checkout = new DateTime($data['check_out']);
            $nights = $checkout->diff($checkin)->days;

            if ($nights <= 0) {
                return ['success' => false, 'message' => 'Invalid dates'];
            }

            // Generate booking reference
            $booking_ref = 'HV-' . strtoupper(substr(uniqid('', true), -8, 8));

            // Generate guest token
            $guest_token = 'bk_' . bin2hex(random_bytes(8));

            // Insert booking
            $stmt = $this->db->prepare("
                INSERT INTO bookings (
                    booking_reference, guest_id, property_id, room_id,
                    check_in, check_out, nights, price, status, 
                    source, guest_token, notes, created_at, updated_at
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
            ");

            $stmt->execute([
                $booking_ref,
                $data['guest_id'],
                $data['property_id'],
                $data['room_id'] ?? null,
                $data['check_in'],
                $data['check_out'],
                $nights,
                $data['price'],
                $data['status'] ?? 'confirmed',
                $data['source'] ?? 'direct',
                $guest_token,
                $data['notes'] ?? null
            ]);

            $booking_id = $this->db->lastInsertId();

            // Log activity
            $this->logActivity($data['user_id'] ?? null, 'booking.create', 'booking', $booking_id, $booking_ref);

            // Send confirmation email (will be implemented in email service)
            $this->queueEmail([
                'type' => 'booking_confirmation',
                'booking_id' => $booking_id,
                'guest_id' => $data['guest_id'],
                'token' => $guest_token
            ]);

            return [
                'success' => true,
                'message' => 'Booking created successfully',
                'booking_id' => $booking_id,
                'booking_reference' => $booking_ref,
                'guest_token' => $guest_token
            ];

        } catch (Exception $e) {
            error_log('Error creating booking: ' . $e->getMessage());
            return ['success' => false, 'message' => 'Error creating booking'];
        }
    }

    /**
     * PUT /api/bookings/{id}
     * Update booking
     */
    public function update($id, $data) {
        try {
            $updates = [];
            $params = [];

            // Allowed fields to update
            $allowed = ['room_id', 'check_in', 'check_out', 'price', 'status', 'notes'];

            foreach ($allowed as $field) {
                if (isset($data[$field])) {
                    $updates[] = "$field = ?";
                    $params[] = $data[$field];
                }
            }

            if (empty($updates)) {
                return ['success' => false, 'message' => 'No fields to update'];
            }

            $updates[] = "updated_at = NOW()";
            $params[] = $id;

            $query = "UPDATE bookings SET " . implode(', ', $updates) . " WHERE id = ?";

            $stmt = $this->db->prepare($query);
            $stmt->execute($params);

            // Log activity
            $this->logActivity($data['user_id'] ?? null, 'booking.update', 'booking', $id);

            return ['success' => true, 'message' => 'Booking updated successfully'];

        } catch (Exception $e) {
            error_log('Error updating booking: ' . $e->getMessage());
            return ['success' => false, 'message' => 'Error updating booking'];
        }
    }

    /**
     * DELETE /api/bookings/{id}
     * Cancel booking
     */
    public function cancel($id, $reason = null) {
        try {
            // Soft delete - just update status
            $stmt = $this->db->prepare("
                UPDATE bookings 
                SET status = 'cancelled', updated_at = NOW()
                WHERE id = ?
            ");
            $stmt->execute([$id]);

            // Log activity
            $this->logActivity(null, 'booking.cancel', 'booking', $id, $reason);

            return ['success' => true, 'message' => 'Booking cancelled'];

        } catch (Exception $e) {
            return ['success' => false, 'message' => 'Error cancelling booking'];
        }
    }

    /**
     * POST /api/bookings/{id}/guest-link
     * Generate/regenerate guest access link
     */
    public function generateGuestLink($id) {
        try {
            $token = 'bk_' . bin2hex(random_bytes(8));

            $stmt = $this->db->prepare("
                UPDATE bookings 
                SET guest_token = ?, updated_at = NOW()
                WHERE id = ?
            ");
            $stmt->execute([$token, $id]);

            $link = $this->config['app']['url'] . '/guest-access.html?token=' . $token;

            return [
                'success' => true,
                'token' => $token,
                'link' => $link
            ];

        } catch (Exception $e) {
            return ['success' => false, 'message' => 'Error generating link'];
        }
    }

    /**
     * GET /api/bookings/guest/{token}
     * Get booking by guest token (for guest portal)
     */
    public function getByGuestToken($token) {
        try {
            $stmt = $this->db->prepare("
                SELECT b.*, g.*, p.name as property_name, r.name as room_name
                FROM bookings b
                JOIN guests g ON b.guest_id = g.id
                JOIN properties p ON b.property_id = p.id
                LEFT JOIN rooms r ON b.room_id = r.id
                WHERE b.guest_token = ?
            ");
            $stmt->execute([$token]);
            $booking = $stmt->fetch(PDO::FETCH_ASSOC);

            if (!$booking) {
                return ['success' => false, 'message' => 'Booking not found'];
            }

            return ['success' => true, 'booking' => $booking];

        } catch (Exception $e) {
            return ['success' => false, 'message' => 'Error fetching booking'];
        }
    }

    /**
     * GET /api/bookings/availability
     * Check room availability
     */
    public function checkAvailability($data) {
        try {
            $stmt = $this->db->prepare("
                SELECT b.check_in, b.check_out
                FROM bookings b
                WHERE b.property_id = ? 
                AND b.room_id = ?
                AND b.status != 'cancelled'
                AND (
                    (b.check_in <= ? AND b.check_out > ?)
                    OR (b.check_in < ? AND b.check_out >= ?)
                    OR (b.check_in >= ? AND b.check_out <= ?)
                )
            ");

            $stmt->execute([
                $data['property_id'],
                $data['room_id'],
                $data['check_out'],
                $data['check_in'],
                $data['check_out'],
                $data['check_in'],
                $data['check_in'],
                $data['check_out']
            ]);

            $conflicts = $stmt->fetchAll(PDO::FETCH_ASSOC);

            return [
                'success' => true,
                'available' => empty($conflicts),
                'conflicts' => $conflicts
            ];

        } catch (Exception $e) {
            return ['success' => false, 'message' => 'Error checking availability'];
        }
    }

    /**
     * Helper: Queue email
     */
    private function queueEmail($email_data) {
        try {
            $stmt = $this->db->prepare("
                INSERT INTO event_queue (event_type, data, status, created_at)
                VALUES (?, ?, 'pending', NOW())
            ");
            $stmt->execute([
                'email',
                json_encode($email_data)
            ]);
        } catch (Exception $e) {
            error_log('Error queuing email: ' . $e->getMessage());
        }
    }

    /**
     * Helper: Log activity
     */
    private function logActivity($user_id, $action, $entity_type, $entity_id, $description = null) {
        try {
            $stmt = $this->db->prepare("
                INSERT INTO activity_log (user_id, action, entity_type, entity_id, description, ip, user_agent)
                VALUES (?, ?, ?, ?, ?, ?, ?)
            ");
            $stmt->execute([
                $user_id,
                $action,
                $entity_type,
                $entity_id,
                $description,
                $_SERVER['REMOTE_ADDR'] ?? '',
                $_SERVER['HTTP_USER_AGENT'] ?? ''
            ]);
        } catch (Exception $e) {
            error_log('Error logging activity: ' . $e->getMessage());
        }
    }
}
