<?php

namespace Modules\ClinicCore\Entities;

use Illuminate\Database\Eloquent\Model;

class ClcDoctorSchedule extends Model
{
    protected $table = 'clc_doctor_schedules';
    protected $guarded = ['id'];

    // SIFA P3-T7 — schedule-pattern casts (all additive, null/default on legacy rows).
    protected $casts = [
        'effective_from'      => 'date',
        'effective_to'        => 'date',
        'max_per_slot'        => 'integer',
        'overbooking_allowed' => 'boolean',
        'overbooking_max'     => 'integer',
    ];

    const DAYS = [
        0 => 'Sunday', 1 => 'Monday', 2 => 'Tuesday', 3 => 'Wednesday',
        4 => 'Thursday', 5 => 'Friday', 6 => 'Saturday',
    ];

    public function doctor()
    {
        return $this->belongsTo(ClcDoctor::class, 'doctor_id');
    }

    public function department()
    {
        return $this->belongsTo(ClcDepartment::class, 'department_id');
    }

    /** SIFA P3-T7 — branch (business_locations) this pattern is scoped to. */
    public function location()
    {
        return $this->belongsTo(\App\BusinessLocation::class, 'location_id');
    }

    /**
     * SIFA P3-T7 — is this pattern in force on a given date? Respects the
     * effective_from / effective_to window (null bound = open-ended). Legacy
     * rows have both null and are therefore always effective.
     */
    public function isEffectiveOn(\DateTimeInterface $date): bool
    {
        $d = $date instanceof \Carbon\CarbonInterface
            ? $date->copy()->startOfDay()
            : \Illuminate\Support\Carbon::parse($date->format('Y-m-d'))->startOfDay();

        if ($this->effective_from && $d->lt($this->effective_from->copy()->startOfDay())) {
            return false;
        }
        if ($this->effective_to && $d->gt($this->effective_to->copy()->startOfDay())) {
            return false;
        }
        return true;
    }

    /** SIFA P3-T7 — the schedule's [break_from, break_to] pair, or null. */
    public function breakInterval(): ?array
    {
        if (empty($this->break_from) || empty($this->break_to)) {
            return null;
        }
        return [substr((string) $this->break_from, 0, 5), substr((string) $this->break_to, 0, 5)];
    }

    public function getDayNameAttribute()
    {
        return self::DAYS[$this->day_of_week] ?? '—';
    }

    /** Return array of HH:MM slot start times (legacy) */
    public function getSlots(): array
    {
        return array_column($this->getSlotPairs(), 'start');
    }

    /**
     * Return array of {start, end} slot pairs.
     *
     * SIFA P3-T7: any slot that overlaps the schedule's break period
     * (break_from..break_to) is dropped. Legacy rows have no break set, so this
     * is a no-op for them and existing behaviour is unchanged.
     */
    public function getSlotPairs(): array
    {
        $pairs = [];
        $start = strtotime($this->start_time);
        $end   = strtotime($this->end_time);
        $step  = (int) $this->slot_duration_minutes * 60;
        if ($step <= 0) return $pairs;

        $break     = $this->breakInterval();
        $breakFrom = $break ? strtotime($break[0]) : null;
        $breakTo   = $break ? strtotime($break[1]) : null;

        for ($t = $start; $t + $step <= $end; $t += $step) {
            // Skip a slot that overlaps [break_from, break_to).
            if ($break && $t < $breakTo && ($t + $step) > $breakFrom) {
                continue;
            }
            $pairs[] = [
                'start'    => date('H:i', $t),
                'end'      => date('H:i', $t + $step),
                'duration' => (int) $this->slot_duration_minutes,
            ];
        }
        return $pairs;
    }

    public function scopeActive($query)
    {
        return $query->where('status', 'active');
    }
}
