<?php
declare(strict_types=1);
namespace App\Repositories;

use App\Core\Repository;

final class StudioRepository extends Repository {
    public function searchBookings(string $q = '', string $date = ''): array {
        $params = [];
        $where = [];
        if ($date !== '') {
            $where[] = 'b.booking_date=?';
            $params[] = $date;
        }
        if ($q !== '') {
            $where[] = '(c.full_name LIKE ? OR c.phone LIKE ? OR c.civil_id LIKE ?)';
            $like = '%' . $q . '%';
            $params[] = $like;
            $params[] = $like;
            $params[] = $like;
        }
        $sql = "SELECT b.*, c.full_name, c.phone, c.civil_id, c.is_blacklisted, c.blacklist_reason, u.full_name AS created_by_name
                FROM studio_bookings b
                JOIN customers c ON c.id = b.customer_id
                LEFT JOIN users u ON u.id = b.created_by";
        if ($where) {
            $sql .= ' WHERE ' . implode(' AND ', $where);
        }
        $sql .= ' ORDER BY b.booking_date DESC, b.start_time ASC, b.id DESC';
        return $this->all($sql, $params);
    }

    public function bookedSlotsByDate(string $date, ?int $exceptId = null): array {
        $sql = 'SELECT start_time FROM studio_bookings WHERE booking_date=?';
        $params = [$date];
        if ($exceptId !== null && $exceptId > 0) {
            $sql .= ' AND id<>?';
            $params[] = $exceptId;
        }
        $rows = $this->all($sql . ' ORDER BY start_time ASC', $params);
        return array_values(array_map(static fn(array $r): string => substr((string)$r['start_time'], 0, 5), $rows));
    }

    public function findBooking(int $id): ?array {
        return $this->one(
            "SELECT b.*, c.full_name, c.phone, c.civil_id, c.is_blacklisted, c.blacklist_reason
             FROM studio_bookings b
             JOIN customers c ON c.id = b.customer_id
             WHERE b.id=? LIMIT 1",
            [$id]
        );
    }

    public function createBooking(int $customerId, string $bookingDate, string $startTime, float $price, int $userId): int {
        $endTime = $this->addHour($startTime);
        if ($this->slotExists($bookingDate, $startTime, null)) {
            throw new \RuntimeException('هذه الساعة محجوزة مسبقاً في نفس التاريخ');
        }
        return $this->insert(
            "INSERT INTO studio_bookings(customer_id, booking_date, start_time, end_time, price, created_by, updated_by, created_at, updated_at)
             VALUES(?,?,?,?,?,?,?,NOW(),NOW())",
            [$customerId, $bookingDate, $startTime . ':00', $endTime . ':00', number_format($price, 3, '.', ''), $userId, $userId]
        );
    }

    public function updateBooking(int $id, int $customerId, string $bookingDate, string $startTime, float $price, int $userId): void {
        $endTime = $this->addHour($startTime);
        if ($this->slotExists($bookingDate, $startTime, $id)) {
            throw new \RuntimeException('هذه الساعة محجوزة مسبقاً في نفس التاريخ');
        }
        $this->exec(
            "UPDATE studio_bookings
             SET customer_id=?, booking_date=?, start_time=?, end_time=?, price=?, updated_by=?, updated_at=NOW()
             WHERE id=?",
            [$customerId, $bookingDate, $startTime . ':00', $endTime . ':00', number_format($price, 3, '.', ''), $userId, $id]
        );
    }

    public function deleteBooking(int $id): int {
        return $this->exec('DELETE FROM studio_bookings WHERE id=? LIMIT 1', [$id]);
    }

    private function slotExists(string $bookingDate, string $startTime, ?int $exceptId): bool {
        $sql = 'SELECT id FROM studio_bookings WHERE booking_date=? AND start_time=?';
        $params = [$bookingDate, $startTime . ':00'];
        if ($exceptId !== null && $exceptId > 0) {
            $sql .= ' AND id<>?';
            $params[] = $exceptId;
        }
        return $this->one($sql . ' LIMIT 1', $params) !== null;
    }

    private function addHour(string $startTime): string {
        [$hour] = explode(':', $startTime, 2);
        $h = ((int)$hour + 1) % 24;
        return str_pad((string)$h, 2, '0', STR_PAD_LEFT) . ':00';
    }
}
