<?php

namespace Modules\Bms\Services\Tasks;

use Illuminate\Support\Carbon;
use Modules\Bms\Entities\BmsBooking;
use Modules\Bms\Entities\BmsTask;
use Modules\Bms\Entities\BmsTaskTemplate;

/**
 * Task template engine (scenario 2.4). On booking confirmation it instantiates
 * per-department task sets from the admin-defined templates, each with a due
 * time relative to the event date.
 */
class TaskService
{
    /** Sensible defaults seeded the first time a business has no templates. */
    public const DEFAULTS = [
        ['title' => 'Send signed contract',        'department' => 'sales',      'offset_days' => -14, 'offset_hour' => 10],
        ['title' => 'Collect deposit (50%)',       'department' => 'finance',    'offset_days' => -30, 'offset_hour' => 10],
        ['title' => 'Kitchen order & prep list',   'department' => 'kitchen',    'offset_days' => -1,  'offset_hour' => 6],
        ['title' => 'Hall setup & décor',          'department' => 'logistics',  'offset_days' => -1,  'offset_hour' => 8],
        ['title' => 'Run-sheet & staff briefing',  'department' => 'operations', 'offset_days' => 0,   'offset_hour' => 12],
        ['title' => 'Final QC walkthrough',        'department' => 'operations', 'offset_days' => 0,   'offset_hour' => 16],
        ['title' => 'Collect balance',             'department' => 'finance',    'offset_days' => -3,  'offset_hour' => 10],
    ];

    /**
     * Instantiate tasks for a confirmed booking. Idempotent — does nothing if
     * the booking already has tasks.
     *
     * @return int  number of tasks created
     */
    public function generateForBooking(BmsBooking $booking): int
    {
        if (BmsTask::where('booking_id', $booking->id)->exists()) {
            return 0;
        }

        $businessId = (int) $booking->business_id;
        $this->ensureDefaults($businessId);

        $templates = BmsTaskTemplate::where('business_id', $businessId)
            ->where('is_active', true)
            ->forEventType($booking->event_type)
            ->orderBy('offset_days')
            ->get();

        $eventDate = $booking->event_date ? Carbon::parse($booking->event_date) : now()->addMonth();

        $created = 0;
        foreach ($templates as $tpl) {
            $dueAt = $eventDate->copy()->addDays($tpl->offset_days)->setTime($tpl->offset_hour ?? 9, 0);
            BmsTask::create([
                'business_id'   => $businessId,
                'booking_id'    => $booking->id,
                'template_id'   => $tpl->id,
                'title'         => $tpl->title,
                'department'    => $tpl->department,
                'due_at'        => $dueAt,
                'assignee_role' => $tpl->assignee_role,
                'status'        => 'pending',
            ]);
            $created++;
        }

        return $created;
    }

    /** Seed default templates the first time (per business). */
    public function ensureDefaults(int $businessId): void
    {
        if (BmsTaskTemplate::where('business_id', $businessId)->exists()) {
            return;
        }
        foreach (self::DEFAULTS as $i => $d) {
            BmsTaskTemplate::create(array_merge($d, [
                'business_id' => $businessId,
                'is_active'   => true,
                'sort_order'  => $i + 1,
            ]));
        }
    }

    public function complete(BmsTask $task, ?int $userId = null): BmsTask
    {
        $task->update([
            'status'       => 'done',
            'completed_at' => now(),
            'completed_by' => $userId,
        ]);
        \Modules\Bms\Entities\BmsTaskEvent::record($task, 'completed', $userId);
        return $task;
    }

    /** Assign (or reassign) a task to a user. */
    public function assign(BmsTask $task, int $userId, ?int $byUserId = null): BmsTask
    {
        $task->update(['assignee_id' => $userId]);
        \Modules\Bms\Entities\BmsTaskEvent::record($task, 'assigned', $byUserId, 'user#' . $userId);
        return $task->fresh();
    }

    /**
     * Mark a task seen by the viewer — stamps received_at (first time) + read_at,
     * logging a 'read' event once. Called when a task detail is opened.
     */
    public function markRead(BmsTask $task, ?int $userId = null): BmsTask
    {
        $attrs = ['read_at' => now()];
        $logReceived = false;
        if (! $task->received_at) {
            $attrs['received_at'] = now();
            $logReceived = true;
        }
        $alreadyRead = (bool) $task->read_at;
        $task->update($attrs);

        if ($logReceived) {
            \Modules\Bms\Entities\BmsTaskEvent::record($task, 'received', $userId);
        }
        if (! $alreadyRead) {
            \Modules\Bms\Entities\BmsTaskEvent::record($task, 'read', $userId);
        }
        return $task->fresh();
    }

    /** The assignee accepts the task (acknowledges ownership). */
    public function accept(BmsTask $task, ?int $userId = null): BmsTask
    {
        $task->update(['accepted_at' => now(), 'accepted_by' => $userId]);
        \Modules\Bms\Entities\BmsTaskEvent::record($task, 'accepted', $userId);
        return $task->fresh();
    }
}
