<?php

namespace App\Http\Requests;

use App\ScheduledTasks\ActionRegistry;
use App\ScheduledTasks\ScheduledTaskRepository;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rule;
use Mtc\MercuryDataModels\ScheduledTask;

class UpdateScheduledTaskRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize(): bool
    {
        /** @var ScheduledTask|null $task */
        $task = $this->route('scheduled_task');

        // System tasks are read-only: enforced here, not just hidden in the UI
        return Auth::check() && !($task && $task->isSystemManaged());
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array<string, mixed>
     */
    public function rules(): array
    {
        $registry = app(ActionRegistry::class);
        $selectableKeys = $registry->selectable()->keys()->toArray();

        $rules = [
            'name' => ['required', 'string', 'max:150'],
            'enabled' => ['boolean'],
            'overlap_policy' => [Rule::in([ScheduledTask::OVERLAP_SKIP, ScheduledTask::OVERLAP_QUEUE])],
            'trigger_type' => [
                'required',
                Rule::in([
                    ScheduledTask::TRIGGER_SCHEDULE,
                    ScheduledTask::TRIGGER_AFTER_TASK,
                    ScheduledTask::TRIGGER_AFTER_EVENT,
                ]),
            ],
            'parent_task_id' => [
                'nullable',
                'required_if:trigger_type,' . ScheduledTask::TRIGGER_AFTER_TASK,
                'integer',
                Rule::exists('scheduled_tasks', 'id')->whereNull('deleted_at'),
            ],
            'parent_condition' => [
                Rule::in([
                    ScheduledTask::CONDITION_ON_SUCCESS,
                    ScheduledTask::CONDITION_ON_FAILURE,
                    ScheduledTask::CONDITION_ALWAYS,
                ]),
            ],
            'event' => [
                'nullable',
                'required_if:trigger_type,' . ScheduledTask::TRIGGER_AFTER_EVENT,
                Rule::in(array_keys(config('scheduled_tasks.events', []))),
            ],
            'event_filter' => ['nullable', 'string', 'max:100'],
            // Only enforced (and only non-empty) for schedule-triggered tasks; excluded
            // entirely otherwise, so after_task / after_event tasks save without rules.
            'schedule_rules' => [
                'exclude_unless:trigger_type,' . ScheduledTask::TRIGGER_SCHEDULE,
                'required',
                'array',
                'min:1',
            ],
            'schedule_rules.*.frequency' => ['required', Rule::in(ScheduledTask::FREQUENCIES)],
            'schedule_rules.*.time' => ['required', 'date_format:H:i'],
            'schedule_rules.*.day_of_week' => [
                'nullable',
                'required_if:schedule_rules.*.frequency,weekly,biweekly',
                'integer',
                'between:1,7',
            ],
            'schedule_rules.*.day_of_month' => [
                'nullable',
                'required_if:schedule_rules.*.frequency,monthly',
                'integer',
                'between:1,31',
            ],
            'actions' => ['array'],
            'actions.*.id' => ['nullable', 'integer'],
            'actions.*.action_type' => ['required', Rule::in($selectableKeys)],
            'actions.*.run_when' => [Rule::in(['on_success', 'on_failure', 'always'])],
            'actions.*.timeout_seconds' => ['nullable', 'integer', 'between:30,3600'],
            'actions.*.config' => ['array'],
        ];

        // Merge each action's own config rules, keyed onto its row
        foreach ($this->input('actions', []) as $index => $actionData) {
            $action = $registry->resolve($actionData['action_type'] ?? '');

            if ($action) {
                foreach ($action->rules($actionData['config'] ?? []) as $field => $fieldRules) {
                    $rules["actions.{$index}.config.{$field}"] = $fieldRules;
                }
            }
        }

        return $rules;
    }

    /**
     * Add custom validation rules that run after the default Laravel validation rules.
     */
    protected function withValidator($validator): void
    {
        $validator->after(function ($validator) {
            /** @var ScheduledTask|null $task */
            $task = $this->route('scheduled_task');

            if (
                $task
                && $this->input('trigger_type') === ScheduledTask::TRIGGER_AFTER_TASK
                && app(ScheduledTaskRepository::class)
                    ->parentCreatesCycle($task, (int) $this->input('parent_task_id'))
            ) {
                $validator->errors()->add(
                    'parent_task_id',
                    'This parent would create a circular task chain.'
                );
            }
        });
    }
}
