<?php

namespace App\Models;

use Config\Lookups;

/**
 * Housekeeping module — see CreateHousekeepingTasksTable. Completing a
 * task also flips the room's own status (RoomModel::setStatus, 'clean')
 * — see HousekeepingController::complete() — so this module and Room
 * Management never disagree about a room's current state.
 */
class HousekeepingTaskModel extends TenantModel
{
    protected $table            = 'housekeeping_tasks';
    protected $primaryKey       = 'id';
    protected $useAutoIncrement = true;
    protected $returnType       = 'object';
    protected $useTimestamps    = true;

    protected $allowedFields = [
        'room_id',
        'task_type',
        'priority',
        'status',
        'assigned_to',
        'start_time',
        'completed_at',
        'inspected_at',
        'inspected_by',
        'notes',
    ];

    public function __construct()
    {
        parent::__construct();

        $lookups = new Lookups();

        $this->validationRules = [
            'room_id'   => 'required|integer',
            'task_type' => 'required|in_list[' . implode(',', array_keys($lookups->housekeepingTaskTypes)) . ']',
            'priority'  => 'permit_empty|in_list[' . implode(',', array_keys($lookups->taskPriorities)) . ']',
            'status'    => 'permit_empty|in_list[' . implode(',', array_keys($lookups->housekeepingTaskStatuses)) . ']',
        ];
    }

    public function withDetails()
    {
        return $this->select('housekeeping_tasks.*, rooms.room_number, room_types.name as room_type_name, users.full_name as assigned_to_name')
            ->join('rooms', 'rooms.id = housekeeping_tasks.room_id')
            ->join('room_types', 'room_types.id = rooms.room_type_id')
            ->join('users', 'users.id = housekeeping_tasks.assigned_to', 'left');
    }

    public function countByStatus(string $status): int
    {
        return $this->where('status', $status)->countAllResults();
    }

    public function countCompletedOn(string $date): int
    {
        return $this->where('DATE(completed_at)', $date)->where('status', 'completed')->countAllResults();
    }

    public function countInspected(): int
    {
        return $this->where('inspected_at IS NOT NULL', null, false)->countAllResults();
    }

    /** @return array<string, int> date (Y-m-d) => count completed that day */
    public function completedTrend(int $days = 7): array
    {
        $trend = [];

        for ($i = $days - 1; $i >= 0; $i--) {
            $date          = date('Y-m-d', strtotime("-{$i} days"));
            $trend[$date]  = $this->countCompletedOn($date);
        }

        return $trend;
    }

    /**
     * Most recent completed cleaning for a room — real "Last Cleaned"
     * data for the All Rooms list, not a fabricated timestamp. Null if
     * the room has never had a housekeeping task completed.
     */
    public function lastCompletedForRoom(int $roomId): ?object
    {
        return $this->select('housekeeping_tasks.*, users.full_name as assigned_to_name')
            ->join('users', 'users.id = housekeeping_tasks.assigned_to', 'left')
            ->where('housekeeping_tasks.room_id', $roomId)
            ->where('housekeeping_tasks.status', 'completed')
            ->orderBy('housekeeping_tasks.completed_at', 'desc')
            ->first();
    }

    /**
     * Used by StaffPerformanceController — completed count + average
     * completion minutes per assignee in a date range, derived entirely
     * from real start_time/completed_at timestamps already being
     * recorded, not a new "performance score".
     *
     * @return array<int, array{count: int, avgMinutes: float}>
     */
    public function performanceByAssignee(string $from, string $to): array
    {
        $rows = $this->select('assigned_to, COUNT(*) as task_count, AVG(TIMESTAMPDIFF(MINUTE, start_time, completed_at)) as avg_minutes')
            ->where('status', 'completed')
            ->where('completed_at >=', $from . ' 00:00:00')
            ->where('completed_at <=', $to . ' 23:59:59')
            ->where('assigned_to IS NOT NULL')
            ->groupBy('assigned_to')
            ->findAll();

        $byUser = [];

        foreach ($rows as $row) {
            $byUser[$row->assigned_to] = [
                'count'      => (int) $row->task_count,
                'avgMinutes' => $row->avg_minutes !== null ? round((float) $row->avg_minutes, 1) : 0.0,
            ];
        }

        return $byUser;
    }
}
