<?php

namespace objects;

use classes\db;
use classes\object_property;
use Exception;
use traits\db_object_t;

class department_time_bookings_opening_hours_o extends db
{
    use db_object_t;

    public object_property $department; // The department id
    public object_property $monday_start; // The start time for Monday
    public object_property $monday_end; // The end time for Monday
    public object_property $tuesday_start; // The start time for Tuesday
    public object_property $tuesday_end; // The end time for Tuesday
    public object_property $wednesday_start; // The start time for Wednesday
    public object_property $wednesday_end; // The end time for Wednesday
    public object_property $thursday_start; // The start time for Thursday
    public object_property $thursday_end; // The end time for Thursday
    public object_property $friday_start; // The start time for Friday
    public object_property $friday_end; // The end time for Friday
    public object_property $saturday_start; // The start time for Saturday
    public object_property $saturday_end; // The end time for Saturday
    public object_property $sunday_start; // The start time for Sunday
    public object_property $sunday_end; // The end time for Sunday

    public function structure(): void
    {
        $this->setTable('department_time_bookings_opening_hours');
    }

    /**
     * Convert the object to an array
     * @throws Exception If the object is not selected
     * @throws Exception If the object is not foun
     */
    public function asArray(): array
    {
        self::requireSelected();
        return [
            'id' => (int)$this->id,
            'department_id' => (int)$this->department->value(),
            'monday_start' => $this->monday_start->value(),
            'monday_end' => $this->monday_end->value(),
            'tuesday_start' => $this->tuesday_start->value(),
            'tuesday_end' => $this->tuesday_end->value(),
            'wednesday_start' => $this->wednesday_start->value(),
            'wednesday_end' => $this->wednesday_end->value(),
            'thursday_start' => $this->thursday_start->value(),
            'thursday_end' => $this->thursday_end->value(),
            'friday_start' => $this->friday_start->value(),
            'friday_end' => $this->friday_end->value(),
            'saturday_start' => $this->saturday_start->value(),
            'saturday_end' => $this->saturday_end->value(),
            'sunday_start' => $this->sunday_start->value(),
            'sunday_end' => $this->sunday_end->value(),
        ];
    }

    /**
     * Select the object by department id
     * @throws Exception
     */
    public function selectByDepartment(int $department_id): void
    {
        // Check if the department has opening hours
        $matches = self::getFieldsWhere([
            'department' => $department_id
        ], [
            'id'
        ]);
        if (count($matches) > 0) {
            $this->id = $matches[0]['id'];
            self::getObjectProperties();
        } else {
            // Create a new object if it doesn't exist
            $this->add($department_id);
        }
    }

    public function getObjectProperties(): void
    {
        $this->department = new object_property($this->table, $this->id, 'department', 'int', true);
        $this->monday_start = new object_property($this->table, $this->id, 'monday_start', 'string', true);
        $this->monday_end = new object_property($this->table, $this->id, 'monday_end', 'string', true);
        $this->tuesday_start = new object_property($this->table, $this->id, 'tuesday_start', 'string', true);
        $this->tuesday_end = new object_property($this->table, $this->id, 'tuesday_end', 'string', true);
        $this->wednesday_start = new object_property($this->table, $this->id, 'wednesday_start', 'string', true);
        $this->wednesday_end = new object_property($this->table, $this->id, 'wednesday_end', 'string', true);
        $this->thursday_start = new object_property($this->table, $this->id, 'thursday_start', 'string', true);
        $this->thursday_end = new object_property($this->table, $this->id, 'thursday_end', 'string', true);
        $this->friday_start = new object_property($this->table, $this->id, 'friday_start', 'string', true);
        $this->friday_end = new object_property($this->table, $this->id, 'friday_end', 'string', true);
        $this->saturday_start = new object_property($this->table, $this->id, 'saturday_start', 'string', true);
        $this->saturday_end = new object_property($this->table, $this->id, 'saturday_end', 'string', true);
        $this->sunday_start = new object_property($this->table, $this->id, 'sunday_start', 'string', true);
        $this->sunday_end = new object_property($this->table, $this->id, 'sunday_end', 'string', true);
    }

    /**
     * Add a new object to the database
     * @param int $department_id The department id
     * @param string|null $monday_start The start time for Monday
     * @param string|null $monday_end The end time for Monday
     * @param string|null $tuesday_start The start time for Tuesday
     * @param string|null $tuesday_end The end time for Tuesday
     * @param string|null $wednesday_start The start time for Wednesday
     * @param string|null $wednesday_end The end time for Wednesday
     * @param string|null $thursday_start The start time for Thursday
     * @param string|null $thursday_end The end time for Thursday
     * @param string|null $friday_start The start time for Friday
     * @param string|null $friday_end The end time for Friday
     * @param string|null $saturday_start The start time for Saturday
     * @param string|null $saturday_end The end time for Saturday
     * @param string|null $sunday_start The start time for Sunday
     * @param string|null $sunday_end The end time for Sunday
     * @return void
     * @throws Exception If the object was not created successfully
     */
    public function add(
        int         $department_id,
        null|string $monday_start = null,
        null|string $monday_end = null,
        null|string $tuesday_start = null,
        null|string $tuesday_end = null,
        null|string $wednesday_start = null,
        null|string $wednesday_end = null,
        null|string $thursday_start = null,
        null|string $thursday_end = null,
        null|string $friday_start = null,
        null|string $friday_end = null,
        null|string $saturday_start = null,
        null|string $saturday_end = null,
        null|string $sunday_start = null,
        null|string $sunday_end = null
    ): void
    {
        function ifEmptySetNull($value): string|null
        {
            return empty($value) ? null : $value;
        }

        $tmp_id = self::add_object([
            'department' => (int)$department_id,
            ...(ifEmptySetNull($monday_start) ? ['monday_start' => $monday_start] : []),
            ...(ifEmptySetNull($monday_end) ? ['monday_end' => $monday_end] : []),
            ...(ifEmptySetNull($tuesday_start) ? ['tuesday_start' => $tuesday_start] : []),
            ...(ifEmptySetNull($tuesday_end) ? ['tuesday_end' => $tuesday_end] : []),
            ...(ifEmptySetNull($wednesday_start) ? ['wednesday_start' => $wednesday_start] : []),
            ...(ifEmptySetNull($wednesday_end) ? ['wednesday_end' => $wednesday_end] : []),
            ...(ifEmptySetNull($thursday_start) ? ['thursday_start' => $thursday_start] : []),
            ...(ifEmptySetNull($thursday_end) ? ['thursday_end' => $thursday_end] : []),
            ...(ifEmptySetNull($friday_start) ? ['friday_start' => $friday_start] : []),
            ...(ifEmptySetNull($friday_end) ? ['friday_end' => $friday_end] : []),
            ...(ifEmptySetNull($saturday_start) ? ['saturday_start' => $saturday_start] : []),
            ...(ifEmptySetNull($saturday_end) ? ['saturday_end' => $saturday_end] : []),
            ...(ifEmptySetNull($sunday_start) ? ['sunday_start' => $sunday_start] : []),
            ...(ifEmptySetNull($sunday_end) ? ['sunday_end' => $sunday_end] : [])
        ]);
        $this->id = $tmp_id;
        self::getObjectProperties();
        self::objectChanged();
    }

    public function objectChanged(): void
    {
        //TODO: Add cache invalidation
    }

    /**
     * Check if the department is open at the given time
     * @param int $start The start timestamp of the booking
     * @param int $end The end timestamp of the booking
     * @return bool True if the department is open, false otherwise
     * @throws Exception If the object is not selected
     */
    public function isOpen(string $start, string $end): bool
    {
        self::requireSelected();
        $start = strtotime($start);
        $end = strtotime($end);
        $dayOfWeek = date('N', $start); // Get the day of the week (1 = Monday, 7 = Sunday)
        // Parse the day of week to the name of the day
        $dayOfWeek = self::getWeekdayName($dayOfWeek);
        $startTime = date('H:i', $start);
        $endTime = date('H:i', $end);
        $openingStart = $this->{"{$dayOfWeek}_start"}->value();
        $openingEnd = $this->{"{$dayOfWeek}_end"}->value();
        if ($openingStart === null || $openingEnd === null) {
            return false; // Closed on this day
        }
        $openingStartTime = date('H:i', strtotime($openingStart));
        $openingEndTime = date('H:i', strtotime($openingEnd));
        return ($startTime >= $openingStartTime && $endTime <= $openingEndTime);
    }

    /**
     * Get the name of the day of the week
     * @param int $dayOfWeek The day of the week (1 = Monday, 7 = Sunday)
     * @return string The name of the day
     * @throws Exception
     */
    private function getWeekdayName(int $dayOfWeek): string
    {
        return match ($dayOfWeek) {
            1 => 'monday',
            2 => 'tuesday',
            3 => 'wednesday',
            4 => 'thursday',
            5 => 'friday',
            6 => 'saturday',
            7 => 'sunday',
            default => throw new Exception('Invalid day of the week'),
        };
    }
}