<?php
// models/Jadwal.php

require_once dirname(__DIR__) . '/models/BaseModel.php';
require_once __DIR__ . '/Detail_Pemesanan.php'; // Penting: Include model Detail_Pemesanan

class Jadwal extends BaseModel {
    protected $table = 'jadwal';

    /**
     * Konstruktor untuk Jadwal.
     * Menerima objek koneksi MySQLi dan meneruskannya ke BaseModel.
     * @param mysqli $conn Objek koneksi database MySQLi.
     */
    public function __construct(mysqli $conn) {
        parent::__construct($conn);
    }

    /**
     * Mengambil semua jadwal tayang yang akan datang, diurutkan berdasarkan tanggal dan waktu.
     * Termasuk informasi film, kategori, dan studio terkait.
     * Sekarang akan mengembalikan studio_id juga.
     *
     * @return array Array asosiatif berisi semua data jadwal yang akan datang.
     */
    public function getAllJadwal() {
        $sql = "SELECT j.*, f.judul AS film_judul, f.cover, f.studio_id AS studio_id, s.nama AS studio_nama, k.kategori
                FROM {$this->table} j
                JOIN film f ON j.film_id = f.id
                JOIN studio s ON f.studio_id = s.id
                JOIN kategori k ON f.kategori_id = k.id
                WHERE j.tanggal_tayang >= CURDATE()
                ORDER BY j.tanggal_tayang ASC, j.waktu_tayang ASC";
        $result = $this->conn->query($sql);
        if (!$result) {
            error_log("SQL Error in getAllJadwal: " . $this->conn->error);
            return [];
        }
        $jadwal = [];
        if ($result->num_rows > 0) {
            while ($row = $result->fetch_assoc()) {
                $jadwal[] = $row;
            }
        }
        return $jadwal;
    }

    /**
     * Mengambil jadwal tayang berdasarkan ID.
     * Termasuk informasi film, kategori, dan studio terkait.
     *
     * @param int $id ID jadwal.
     * @return array|null Array asosiatif data jadwal jika ditemukan, null jika tidak.
     */
    public function getJadwalById($id) {
        $sql = "SELECT j.*, f.judul AS film_judul, f.sinopsis, f.cover,
                                 s.id AS studio_id, s.nama AS studio_nama, k.kategori
                FROM {$this->table} j
                JOIN film f ON j.film_id = f.id
                JOIN studio s ON f.studio_id = s.id
                JOIN kategori k ON f.kategori_id = k.id
                WHERE j.id = ?";
        $stmt = $this->conn->prepare($sql);
        if (!$stmt) {
            error_log("Prepare failed in getJadwalById: " . $this->conn->error);
            return null;
        }
        $stmt->bind_param("i", $id);
        if (!$stmt->execute()) {
            error_log("Execute failed in getJadwalById: " . $stmt->error);
            return null;
        }
        $result = $stmt->get_result();
        return $result->fetch_assoc();
    }

    /**
     * Mengambil jadwal tayang untuk film tertentu, dimulai dari hari ini.
     * Sekarang akan mengembalikan juga studio_id agar bisa digunakan untuk grouping di frontend.
     *
     * @param int $film_id ID film.
     * @return array Array asosiatif berisi data jadwal film.
     */
    public function getJadwalByFilmId($film_id) {
        $sql = "SELECT j.*, f.judul AS film_judul, f.studio_id AS studio_id, s.nama AS studio_nama
                FROM {$this->table} j
                JOIN film f ON j.film_id = f.id
                JOIN studio s ON f.studio_id = s.id
                WHERE j.film_id = ? AND j.tanggal_tayang >= CURDATE()
                ORDER BY j.tanggal_tayang ASC, j.waktu_tayang ASC";
        $stmt = $this->conn->prepare($sql);
        if (!$stmt) {
            error_log("Prepare failed in getJadwalByFilmId: " . $this->conn->error);
            return [];
        }
        $stmt->bind_param("i", $film_id);
        if (!$stmt->execute()) {
            error_log("Execute failed in getJadwalByFilmId: " . $stmt->error);
            return [];
        }
        $result = $stmt->get_result();
        $jadwal = [];
        if ($result->num_rows > 0) {
            while ($row = $result->fetch_assoc()) {
                $jadwal[] = $row;
            }
        }
        return $jadwal;
    }

    /**
     * Mendapatkan semua kursi di studio yang terkait dengan jadwal, dan status ketersediaannya.
     *
     * @param int $jadwal_id ID jadwal tayang.
     * @return array Array asosiatif berisi data kursi dan status (available/booked).
     */
    public function getKursiStatusByJadwal($jadwal_id) {
        $jadwal_info = $this->getJadwalById($jadwal_id);
        if (!$jadwal_info) {
            error_log("Jadwal ID {$jadwal_id} not found in getKursiStatusByJadwal.");
            return [];
        }
        $studio_id = $jadwal_info['studio_id'];

        $sql_all_kursi = "SELECT id, nomor FROM kursi WHERE studio_id = ? ORDER BY nomor ASC";
        $stmt_all = $this->conn->prepare($sql_all_kursi);
        if (!$stmt_all) {
            error_log("Prepare failed for getAllKursi in getKursiStatusByJadwal: " . $this->conn->error);
            return [];
        }
        $stmt_all->bind_param("i", $studio_id);
        if (!$stmt_all->execute()) {
            error_log("Execute failed for getAllKursi in getKursiStatusByJadwal: " . $stmt_all->error);
            return [];
        }
        $result_all = $stmt_all->get_result();
        $all_kursi = [];
        while ($row = $result_all->fetch_assoc()) {
            $all_kursi[$row['id']] = $row;
            $all_kursi[$row['id']]['status'] = 'available';
        }

        $sql_booked_kursi = "SELECT kursi_id FROM detail_pemesanan WHERE jadwal_id = ? AND status_pemesanan IN ('pending', 'paid')";
        $stmt_booked = $this->conn->prepare($sql_booked_kursi);
        if (!$stmt_booked) {
            error_log("Prepare failed for getBookedKursi in getKursiStatusByJadwal: " . $this->conn->error);
            return array_values($all_kursi);
        }
        $stmt_booked->bind_param("i", $jadwal_id);
        if (!$stmt_booked->execute()) {
            error_log("Execute failed for getBookedKursi in getKursiStatusByJadwal: " . $stmt_booked->error);
            return array_values($all_kursi);
        }
        $result_booked = $stmt_booked->get_result();
        while ($row = $result_booked->fetch_assoc()) {
            if (isset($all_kursi[$row['kursi_id']])) {
                $all_kursi[$row['kursi_id']]['status'] = 'booked';
            }
        }
        return array_values($all_kursi);
    }

    /**
     * Membuat jadwal tayang baru ke database.
     * Menggunakan nama 'createJadwal' untuk konsistensi.
     *
     * @param int $film_id ID film.
     * @param string $tanggal_tayang Tanggal tayang (formatYYYY-MM-DD).
     * @param string $waktu_tayang Waktu tayang (format HH:MM:SS).
     * @param float $harga_tiket Harga tiket untuk jadwal ini.
     * @return bool True jika berhasil, false jika gagal.
     */
    public function createJadwal($film_id, $tanggal_tayang, $waktu_tayang, $harga_tiket) {
        error_log("DEBUG: createJadwal menerima - Film ID: {$film_id}, Tanggal: {$tanggal_tayang}, Waktu: {$waktu_tayang}, Harga: {$harga_tiket}");

        // Menggunakan fungsi STR_TO_DATE() di SQL untuk memastikan parsing yang benar
        $stmt = $this->conn->prepare("INSERT INTO {$this->table} (film_id, tanggal_tayang, waktu_tayang, harga_tiket) VALUES (?, ?, STR_TO_DATE(?, '%H:%i:%s'), ?)");
        
        if (!$stmt) {
            error_log("Prepare failed in createJadwal: " . $this->conn->error);
            return false;
        }
        $stmt->bind_param("isds", $film_id, $tanggal_tayang, $waktu_tayang, $harga_tiket);
        
        if ($stmt->execute()) {
            error_log("DEBUG: createJadwal - SQL Execute BERHASIL.");
            return true;
        } else {
            error_log("DEBUG: createJadwal - SQL Execute GAGAL. Error: " . $stmt->error);
            return false;
        }
    }

    /**
     * Memperbarui data jadwal tayang yang sudah ada di database.
     *
     * @param int $id ID jadwal yang akan diperbarui.
     * @param int $film_id ID film.
     * @param string $tanggal_tayang Tanggal tayang baru.
     * @param string $waktu_tayang Waktu tayang baru.
     * @param float $harga_tiket Harga tiket baru.
     * @return bool True jika berhasil, false jika gagal.
     */
    public function updateJadwal($id, $film_id, $tanggal_tayang, $waktu_tayang, $harga_tiket) {
        // Menggunakan fungsi STR_TO_DATE() di SQL untuk memastikan parsing yang benar
        $sql = "UPDATE {$this->table} SET film_id = ?, tanggal_tayang = ?, waktu_tayang = STR_TO_DATE(?, '%H:%i:%s'), harga_tiket = ? WHERE id = ?";
        
        $stmt = $this->conn->prepare($sql);
        if (!$stmt) {
            error_log("Prepare failed in updateJadwal: " . $this->conn->error);
            return false;
        }
        $stmt->bind_param("issdi", $film_id, $tanggal_tayang, $waktu_tayang, $harga_tiket, $id);
        
        if ($stmt->execute()) {
            return true;
        } else {
            error_log("Execute failed in updateJadwal: " . $stmt->error);
            return false;
        }
    }

    /**
     * Menghapus jadwal tayang dari database berdasarkan ID.
     * Sekarang akan juga menghapus detail pemesanan terkait.
     *
     * @param int $id ID jadwal yang akan dihapus.
     * @return bool True jika berhasil, false jika gagal.
     */
    public function deleteJadwal($id) {
        $detailPemesananModel = new Detail_Pemesanan($this->conn);

        if (!$detailPemesananModel->deleteByJadwalId($id)) {
            error_log("Gagal menghapus detail pemesanan untuk jadwal ID {$id}. Tidak dapat menghapus jadwal.");
            return false;
        }

        $stmt = $this->conn->prepare("DELETE FROM {$this->table} WHERE id = ?");
        if (!$stmt) {
            error_log("Prepare failed in deleteJadwal (main delete): " . $this->conn->error);
            return false;
        }
        $stmt->bind_param("i", $id);
        if (!$stmt->execute()) {
            error_log("Execute failed in deleteJadwal (main delete): " . $stmt->error);
            return false;
        }
        return true;
    }

    /**
     * Menghapus semua jadwal yang tanggalnya sudah lewat dari tanggal tertentu.
     * Dipanggil oleh JadwalController::ensureSchedulesUpToDate().
     * Sekarang akan menghapus detail pemesanan terkait terlebih dahulu.
     * @param string $date Batas tanggal (format Y-m-d). Jadwal sebelum tanggal ini akan dihapus.
     * @return bool
     */
    public function deleteOldSchedules($date) {
        $detailPemesananModel = new Detail_Pemesanan($this->conn);

        $sql_get_ids = "SELECT id FROM {$this->table} WHERE tanggal_tayang < ?";
        $stmt_get = $this->conn->prepare($sql_get_ids);
        if (!$stmt_get) {
            error_log("Prepare failed for getting old schedule IDs: " . $this->conn->error);
            return false;
        }
        $stmt_get->bind_param("s", $date);
        if (!$stmt_get->execute()) {
            error_log("Execute failed for getting old schedule IDs: " . $stmt_get->error);
            return false;
        }
        $result_ids = $stmt_get->get_result();
        $ids_to_delete = [];
        while ($row = $result_ids->fetch_assoc()) {
            $ids_to_delete[] = $row['id'];
        }

        foreach ($ids_to_delete as $jadwal_id) {
            if (!$detailPemesananModel->deleteByJadwalId($jadwal_id)) {
                error_log("Gagal menghapus detail pemesanan untuk jadwal lama ID {$jadwal_id}. Lanjut ke jadwal berikutnya.");
            }
        }

        if (!empty($ids_to_delete)) {
            $placeholders = implode(',', array_fill(0, count($ids_to_delete), '?'));
            $types = str_repeat('i', count($ids_to_delete));

            $sql_delete_jadwal = "DELETE FROM {$this->table} WHERE id IN ({$placeholders})";
            $stmt_delete_jadwal = $this->conn->prepare($sql_delete_jadwal);
            if (!$stmt_delete_jadwal) {
                error_log("Prepare failed in deleteOldSchedules (main delete using IN): " . $this->conn->error);
                return false;
            }
            $stmt_delete_jadwal->bind_param($types, ...$ids_to_delete);

            if (!$stmt_delete_jadwal->execute()) {
                error_log("Execute failed in deleteOldSchedules (main delete using IN): " . $stmt_delete_jadwal->error);
                return false;
            }
        }
        
        return true;
    }

    /**
     * Mengambil tanggal jadwal tayang terbaru yang ada di database.
     * Dipanggil oleh JadwalController::ensureSchedulesUpToDate().
     * @return string|null Tanggal dalam format Y-m-d, atau null jika tidak ada jadwal.
     */
    public function getLastScheduleDate() {
        $sql = "SELECT MAX(tanggal_tayang) AS last_date FROM {$this->table}";
        $result = $this->conn->query($sql);
        if (!$result) {
            error_log("SQL Error in getLastScheduleDate: " . $this->conn->error);
            return null;
        }
        if ($row = $result->fetch_assoc()) {
            return $row['last_date'];
        }
        return null;
    }

    /**
     * Mengecek apakah sebuah jadwal sudah ada untuk film, tanggal, dan waktu tertentu.
     * Ini penting untuk mencegah duplikasi saat generate jadwal.
     * Dipanggil oleh JadwalController::ensureSchedulesUpToDate().
     * @param int $film_id
     * @param string $tanggal_tayang (Y-m-d)
     * @param string $waktu_tayang (H:i:s)
     * @return array|null Mengembalikan baris jadwal jika ditemukan, atau null.
     */
    public function getJadwalByFilmDateAndTime($film_id, $tanggal_tayang, $waktu_tayang) {
        // Menggunakan STR_TO_DATE() untuk perbandingan juga, memastikan konsistensi
        $stmt = $this->conn->prepare("SELECT id FROM {$this->table} WHERE film_id = ? AND tanggal_tayang = ? AND waktu_tayang = STR_TO_DATE(?, '%H:%i:%s')");
            
        if (!$stmt) {
            error_log("Prepare failed in getJadwalByFilmDateAndTime: " . $this->conn->error);
            return null;
        }
        $stmt->bind_param("iss", $film_id, $tanggal_tayang, $waktu_tayang);
        if (!$stmt->execute()) {
            error_log("Execute failed in getJadwalByFilmDateAndTime: " . $stmt->error);
            return null;
        }
        $result = $stmt->get_result();
        return $result->fetch_assoc();
    }

    /**
     * Menghapus jadwal tayang dari database berdasarkan ID film.
     * Metode ini perlu juga menghapus detail pemesanan terkait.
     * @param int $film_id ID film.
     * @return bool True jika berhasil, false jika gagal.
     */
    public function deleteJadwalByFilmId($film_id) {
        $detailPemesananModel = new Detail_Pemesanan($this->conn);

        $sql_get_jadwal_ids = "SELECT id FROM {$this->table} WHERE film_id = ?";
        $stmt_get_jadwal_ids = $this->conn->prepare($sql_get_jadwal_ids);
        if (!$stmt_get_jadwal_ids) {
            error_log("Prepare failed in deleteJadwalByFilmId (get jadwal IDs): " . $this->conn->error);
            return false;
        }
        $stmt_get_jadwal_ids->bind_param("i", $film_id);
        if (!$stmt_get_jadwal_ids->execute()) {
            error_log("Execute failed in deleteJadwalByFilmId (get jadwal IDs): " . $stmt_get_jadwal_ids->error);
            return false;
        }
        $result_jadwal_ids = $stmt_get_jadwal_ids->get_result();
        $jadwal_ids_to_delete = [];
        while ($row = $result_jadwal_ids->fetch_assoc()) {
            $jadwal_ids_to_delete[] = $row['id'];
        }

        foreach ($jadwal_ids_to_delete as $jadwal_id) {
            if (!$detailPemesananModel->deleteByJadwalId($jadwal_id)) {
                error_log("Gagal menghapus detail pemesanan untuk jadwal ID {$jadwal_id} (film ID {$film_id}).");
            }
        }

        if (!empty($jadwal_ids_to_delete)) {
            $placeholders = implode(',', array_fill(0, count($jadwal_ids_to_delete), '?'));
            $types = str_repeat('i', count($jadwal_ids_to_delete));

            $sql_delete_jadwal = "DELETE FROM {$this->table} WHERE id IN ({$placeholders})";
            $stmt_delete_jadwal = $this->conn->prepare($sql_delete_jadwal);
            if (!$stmt_delete_jadwal) {
                error_log("Prepare failed in deleteJadwalByFilmId (main delete): " . $this->conn->error);
                return false;
            }
            $stmt_delete_jadwal->bind_param($types, ...$jadwal_ids_to_delete);
            if (!$stmt_delete_jadwal->execute()) {
                error_log("Execute failed in deleteJadwalByFilmId (main delete): " . $stmt_delete_jadwal->error);
                return false;
            }
        } else {
            return true;
        }

        return true;
    }
}