<?php
require_once __DIR__ . '/../models/Booking.php';
require_once __DIR__ . '/../models/AuditLog.php';
require_once __DIR__ . '/../models/NotificationSchedule.php';
require_once __DIR__ . '/../models/ExtensionRequest.php';
require_once __DIR__ . '/../helpers/Response.php';
require_once __DIR__ . '/../helpers/Validator.php';
require_once __DIR__ . '/../helpers/NotificationHelper.php';

class BookingController
{
    private $db;
    private $booking;
    private $auditLog;
    private $notificationSchedule;
    private $extensionRequest;

    public function __construct($db)
    {
        $this->db = $db;
        $this->booking = new Booking($db);
        $this->auditLog = new AuditLog($db);
        $this->notificationSchedule = new NotificationSchedule($db);
        $this->extensionRequest = new ExtensionRequest($db);
    }

    public function create()
    {
        try {
            $headers = array_change_key_case(getallheaders(), CASE_LOWER);
            $auth = $headers['authorization'] ?? '';
            $user_id = null;
            if (strpos($auth, 'Bearer ') === 0) {
                $token = substr($auth, 7);
                $decoded = base64_decode($token);
                $parts = explode(':', $decoded);
                $user_id = (int) $parts[0];
            }

            $data = json_decode(file_get_contents("php://input"), true);

            $rules = [
                'guesthouse_id' => 'required',
                'entry_time' => 'required',
                'exit_time' => 'required',
                'total_price' => 'required',
                'stay_type' => 'required',
                'stay_duration' => 'required',
                'payment_method' => 'required',
                'payment_phone' => 'required'
            ];

            $errors = Validator::validate($data, $rules);
            if (!empty($errors)) {
                Response::error("Validation Error", 400, $errors);
            }

            $this->booking->guesthouse_id = $data['guesthouse_id'];
            $this->booking->user_id = $user_id; // From token
            $this->booking->entry_time = $data['entry_time'];
            $this->booking->exit_time = $data['exit_time'];
            $this->booking->total_price = $data['total_price'];
            $this->booking->stay_type = $data['stay_type'];
            $this->booking->stay_duration = $data['stay_duration'];
            $this->booking->payment_method = $data['payment_method'];
            $this->booking->payment_phone = $data['payment_phone'];

            if ($this->booking->create()) {
                $this->auditLog->log($this->booking->id, "Reserva criada", null, "Aguardando Entrada", "Usuário iniciou reserva.");

                // Schedule notifications
                $this->scheduleBookingNotifications($this->booking);

                // Notify Owner (Safely)
                try {
                    $this->sendNewBookingNotification($this->booking->id, $data['guesthouse_id']);
                } catch (Throwable $e) {
                    // Log error but don't fail the booking
                    error_log("Notification Error: " . $e->getMessage());
                }

                Response::success("Reserva confirmada.", [
                    "id" => (int) $this->booking->id,
                    "entry_code" => $this->booking->entry_code,
                    "status" => "Aguardando Entrada"
                ]);
            } else {
                Response::error("Erro ao inserir reserva na base de dados.", 503);
            }
        } catch (Exception $e) {
            Response::error("Erro interno do servidor: " . $e->getMessage(), 500);
        } catch (Error $e) {
            Response::error("Erro fatal do servidor: " . $e->getMessage(), 500);
        }
    }

    public function validate()
    {
        $data = json_decode(file_get_contents("php://input"), true);
        $code = $data['entry_code'] ?? '';

        if (empty($code)) {
            Response::error("Código de acesso obrigatório.", 400);
        }

        $bookingData = $this->booking->validateCode($code);

        if (!$bookingData) {
            Response::error("Código inválido ou não encontrado.", 404);
        }

        if ($bookingData['status'] === 'Entrada Confirmada') {
            Response::error("Esta entrada já foi validada anteriormente.", 400);
        }

        $this->booking->id = $bookingData['id'];
        if ($this->booking->updateStatus("Entrada Confirmada")) {
            $this->auditLog->log($this->booking->id, "Entrada validada", $bookingData['status'], "Entrada Confirmada", "Código validado pelo fornecedor.");
            Response::success("Entrada Confirmada com sucesso.", [
                "id" => (int) $bookingData['id'],
                "status" => "Entrada Confirmada",
                "timestamp" => date('Y-m-d H:i:s')
            ]);
        } else {
            Response::error("Erro ao atualizar status da reserva.", 503);
        }
    }

    public function me()
    {
        $headers = array_change_key_case(getallheaders(), CASE_LOWER);
        $auth = $headers['authorization'] ?? '';
        if (strpos($auth, 'Bearer ') === 0) {
            $token = substr($auth, 7);
            $decoded = base64_decode($token);
            $parts = explode(':', $decoded);
            $user_id = (int) $parts[0];
        } else {
            Response::error("Não autorizado.", 401);
            return;
        }

        $query = "SELECT b.*, g.name as guesthouse_name, g.city as guesthouse_city, g.gps_coordinates, g.address as guesthouse_address
                  FROM bookings b 
                  JOIN guesthouses g ON b.guesthouse_id = g.id 
                  WHERE b.user_id = :user_id 
                  ORDER BY b.created_at DESC";

        $stmt = $this->db->prepare($query);
        $stmt->bindParam(":user_id", $user_id);
        $stmt->execute();
        $bookings = $stmt->fetchAll(PDO::FETCH_ASSOC);

        Response::success("Minhas reservas recuperadas.", $bookings);
    }

    public function owner_list()
    {
        $headers = array_change_key_case(getallheaders(), CASE_LOWER);
        $auth = $headers['authorization'] ?? '';
        if (strpos($auth, 'Bearer ') === 0) {
            $token = substr($auth, 7);
            $decoded = base64_decode($token);
            $parts = explode(':', $decoded);
            $user_id = (int) $parts[0];
        } else {
            Response::error("Não autorizado.", 401);
            return;
        }

        $status = $_GET['status'] ?? null;
        $date = $_GET['date'] ?? null;

        $query = "SELECT b.*, g.name as guesthouse_name 
                  FROM bookings b 
                  JOIN guesthouses g ON b.guesthouse_id = g.id 
                  WHERE g.user_id = :user_id";

        if ($status) {
            $query .= " AND b.status = :status";
        }
        if ($date === 'today') {
            $query .= " AND DATE(b.entry_time) = CURDATE()";
        }

        $query .= " ORDER BY b.entry_time ASC";

        $stmt = $this->db->prepare($query);
        $stmt->bindParam(":user_id", $user_id);
        if ($status) {
            $stmt->bindParam(":status", $status);
        }
        $stmt->execute();
        $bookings = $stmt->fetchAll(PDO::FETCH_ASSOC);

        Response::success("Reservas recuperadas.", $bookings);
    }

    public function dashboardStats()
    {
        $headers = array_change_key_case(getallheaders(), CASE_LOWER);
        $auth = $headers['authorization'] ?? '';
        if (strpos($auth, 'Bearer ') === 0) {
            $token = substr($auth, 7);
            $decoded = base64_decode($token);
            $parts = explode(':', $decoded);
            $user_id = (int) $parts[0];
        } else {
            Response::error("Não autorizado.", 401);
            return;
        }

        $stats = [
            'today_bookings' => 0,
            'pending_entries' => 0,
            'today_revenue' => 0.0
        ];

        // Today's total bookings count
        $query = "SELECT COUNT(*) as count 
                  FROM bookings b 
                  JOIN guesthouses g ON b.guesthouse_id = g.id 
                  WHERE g.user_id = :user_id AND DATE(b.created_at) = CURDATE()";
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(":user_id", $user_id);
        $stmt->execute();
        $res = $stmt->fetch(PDO::FETCH_ASSOC);
        $stats['today_bookings'] = (int) ($res['count'] ?? 0);

        // Pending entries for today
        $query = "SELECT COUNT(*) as count 
                  FROM bookings b 
                  JOIN guesthouses g ON b.guesthouse_id = g.id 
                  WHERE g.user_id = :user_id AND b.status = 'Aguardando Entrada' AND DATE(b.entry_time) = CURDATE()";
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(":user_id", $user_id);
        $stmt->execute();
        $res = $stmt->fetch(PDO::FETCH_ASSOC);
        $stats['pending_entries'] = (int) ($res['count'] ?? 0);

        // Today's revenue
        $query = "SELECT SUM(b.total_price) as total 
                  FROM bookings b 
                  JOIN guesthouses g ON b.guesthouse_id = g.id 
                  WHERE g.user_id = :user_id AND DATE(b.created_at) = CURDATE() AND b.status != 'Cancelada'";
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(":user_id", $user_id);
        $stmt->execute();
        $res = $stmt->fetch(PDO::FETCH_ASSOC);
        $stats['today_revenue'] = (double) ($res['total'] ?? 0);

        Response::success("Stats recuperadas.", $stats);
    }

    private function scheduleBookingNotifications($booking)
    {
        $entry_time = strtotime($booking->entry_time);
        $exit_time = strtotime($booking->exit_time);

        if ($booking->stay_type === 'Hour') {
            $entry_notify_at = date('Y-m-d H:i:s', $entry_time - (15 * 60));
            $exit_notify_at = date('Y-m-d H:i:s', $exit_time - (15 * 60));
        } else {
            $entry_notify_at = date('Y-m-d H:i:s', $entry_time - (60 * 60));
            $exit_notify_at = date('Y-m-d H:i:s', $exit_time - (3 * 60 * 60));
        }

        // Only schedule if time is in the future
        if (strtotime($entry_notify_at) > time()) {
            $this->notificationSchedule->create($booking->id, 'ENTRY_REMINDER', $entry_notify_at);
        }
        if (strtotime($exit_notify_at) > time()) {
            $this->notificationSchedule->create($booking->id, 'EXIT_REMINDER', $exit_notify_at);
        }
    }

    public function extensionOptions()
    {
        $id = $_GET['id'] ?? null;
        if (!$id)
            Response::error("ID da reserva obrigatório", 400);

        $bookingData = $this->booking->getById($id);
        if (!$bookingData)
            Response::error("Reserva não encontrada", 404);

        // Fetch guesthouse info to get prices
        $query = "SELECT * FROM guesthouses WHERE id = :id";
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(":id", $bookingData['guesthouse_id']);
        $stmt->execute();
        $gh = $stmt->fetch(PDO::FETCH_ASSOC);

        $options = [];
        if ($bookingData['stay_type'] === 'Hour') {
            $options[] = [
                "duration" => 1,
                "type" => "Hour",
                "price" => (float) $gh['price_per_hour'],
                "label" => "+1 Hora"
            ];
            $options[] = [
                "duration" => 2,
                "type" => "Hour",
                "price" => (float) $gh['price_per_2_hours'],
                "label" => "+2 Horas"
            ];
        } else {
            $options[] = [
                "duration" => 1,
                "type" => "Night",
                "price" => (float) $gh['price_per_night'],
                "label" => "+1 Noite"
            ];
        }

        Response::success("Opções de extensão", [
            "options" => $options,
            "can_extend_directly" => ($bookingData['stay_type'] === 'Hour') // Example rule
        ]);
    }

    public function extend()
    {
        $data = json_decode(file_get_contents("php://input"), true);
        $id = $data['reservation_id'] ?? null;
        $duration = $data['duration'] ?? null;
        $type = $data['type'] ?? null;
        $price = $data['price'] ?? null;

        if (!$id || !$duration || !$type)
            Response::error("Dados incompletos", 400);

        $bookingData = $this->booking->getById($id);
        if (!$bookingData)
            Response::error("Reserva não encontrada", 404);

        // UPDATE end_datetime
        $current_exit = strtotime($bookingData['exit_time']);
        if ($type === 'Hour') {
            $new_exit = date('Y-m-d H:i:s', $current_exit + ($duration * 3600));
        } else {
            $new_exit = date('Y-m-d H:i:s', $current_exit + ($duration * 86400));
        }

        $query = "UPDATE bookings SET exit_time = :exit, total_price = total_price + :price, stay_duration = stay_duration + :dur WHERE id = :id";
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(":exit", $new_exit);
        $stmt->bindParam(":price", $price);
        $stmt->bindParam(":dur", $duration);
        $stmt->bindParam(":id", $id);

        if ($stmt->execute()) {
            $this->auditLog->log($id, "Prolongamento Direto", $bookingData['exit_time'], $new_exit, "Usuário prolongou a estadia.");

            // Reschedule EXIT_REMINDER
            $exit_notify_at = ($type === 'Hour') ?
                date('Y-m-d H:i:s', strtotime($new_exit) - (15 * 60)) :
                date('Y-m-d H:i:s', strtotime($new_exit) - (3 * 3600));

            $this->notificationSchedule->reschedule($id, 'EXIT_REMINDER', $exit_notify_at);

            Response::success("Estadia prolongada com sucesso.", ["new_exit" => $new_exit]);
        } else {
            Response::error("Erro ao prolongar estadia.", 500);
        }
    }

    public function requestExtension()
    {
        $data = json_decode(file_get_contents("php://input"), true);
        $id = $data['reservation_id'] ?? null;
        $duration = $data['duration'] ?? null;
        $type = $data['type'] ?? null;
        $message = $data['message'] ?? '';

        if (!$id || !$duration || !$type)
            Response::error("Dados incompletos", 400);

        if ($this->extensionRequest->create($id, $duration, $type, $message)) {
            $this->auditLog->log($id, "Solicitação de Extensão", "PENDING", "REQUESTED", "Usuário solicitou extensão.");
            Response::success("Solicitação enviada. Aguarde aprovação.");
        } else {
            Response::error("Erro ao enviar solicitação.", 500);
        }
    }

    private function sendNewBookingNotification($bookingId, $guesthouseId)
    {
        // 1. Get Owner User ID from Guesthouse
        $query = "SELECT user_id, name FROM guesthouses WHERE id = :id";
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(":id", $guesthouseId);
        $stmt->execute();
        $gh = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$gh || !$gh['user_id'])
            return;

        // 2. Get Owner FCM Token
        $queryUser = "SELECT fcm_token FROM users WHERE id = :id AND push_enabled = 1";
        $stmtUser = $this->db->prepare($queryUser);
        $stmtUser->bindParam(":id", $gh['user_id']);
        $stmtUser->execute();
        $user = $stmtUser->fetch(PDO::FETCH_ASSOC);

        if ($user && !empty($user['fcm_token'])) {
            NotificationHelper::sendToToken(
                $user['fcm_token'],
                "Nova Reserva!",
                "Recebeu uma nova reserva para {$gh['name']}.",
                ['type' => 'new_booking', 'booking_id' => (string) $bookingId]
            );
        }
    }
}